package com.yanqu.road.server.manager.activity.xiuxian.activity;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.xiuxian.config.XiuXianPeakConfig;
import com.yanqu.road.entity.activity.xiuxian.config.XiuXianPvpPlaceConfig;
import com.yanqu.road.entity.activity.xiuxian.config.XiuXianStateConfig;
import com.yanqu.road.entity.activity.xiuxian.data.*;
import com.yanqu.road.entity.activity.xiuxian.data.helper.CrossXiuXianNpcDataHelper;
import com.yanqu.road.entity.activity.xiuxian.data.helper.CrossXiuXianPvpAttackHelper;
import com.yanqu.road.entity.activity.xiuxian.data.helper.XiuXianGenCampHelper;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eMessageType;
import com.yanqu.road.entity.enums.xiuxian.eXiuXianPvpActivityStateType;
import com.yanqu.road.entity.enums.xiuxian.eXiuXianPvpNoticeType;
import com.yanqu.road.entity.enums.xiuxian.eXiuXianPvpPlaceType;
import com.yanqu.road.entity.enums.xiuxian.eXiuXianType;
import com.yanqu.road.entity.log.cross.LogXiuXianPvpBattle;
import com.yanqu.road.entity.log.cross.LogXiuXianPvpPlaceSeize;
import com.yanqu.road.entity.player.CrossUserBaseInfo;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.logic.bussiness.activity.XiuXianActivityBusiness;
import com.yanqu.road.logic.helper.ActivityHelper;
import com.yanqu.road.logic.pb.CrossXiuXianPb;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.activity.XiuXianProto;
import com.yanqu.road.pb.cross.activity.CrossActivityProto;
import com.yanqu.road.pb.player.PlayerProto;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.pb.worldmessage.WorldMessageProto;
import com.yanqu.road.server.manager.activity.xiuxian.logic.CrossXiuXianChatLogic;
import com.yanqu.road.server.manager.log.CrossAutoLogMgr;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 凡人修仙传
 */
public class CrossXiuXianActivity extends CrossXiuXianBaseActivity {

    private RandomHelper randomHelper = new RandomHelper();

    /**
     * 活动总数据
     */
    private CrossXiuXianPvpData crossXiuXianPvpData;

    /**
     * pvp玩家数据     userId,玩家数据
     */
    private Map<Long, CrossXiuXianPvpUserData> pvpUserDataMap = new ConcurrentHashMap<>();

    /**
     * pvp阵营数据      campId,阵营数据
     */
    private Map<Integer, CrossXiuXianPvpCampData> pvpCampDataMap = new ConcurrentHashMap<>();

    /**
     * 宝地(房间)信息    placeId,房间信息
     */
    private Map<Integer, CrossXiuXianPvpPlaceData> pvpPlaceDataMap = new ConcurrentHashMap<>();

    /**
     * 宗门个人仙力榜单
     */
    private Map<Integer, CrossXiuXianRankListModel> campUserRankMap = new ConcurrentHashMap<>();

    /**
     * 宗门体力使用榜单
     */
    private Map<Integer, CrossXiuXianRankListModel> campEnergyRankMap = new ConcurrentHashMap<>();

    /**
     * 个人战绩榜单
     */
    private CrossXiuXianRankListModel userScoreRank = new CrossXiuXianRankListModel();

    /**
     * 本轮宗门积分榜单
     */
    private CrossXiuXianRankListModel campScoreRankMap = new CrossXiuXianRankListModel();

    /**
     * 活动宗门积分榜单
     */
    private CrossXiuXianRankListModel campTotalScoreRankMap = new CrossXiuXianRankListModel();

    /**
     * 活动结算数据, 轮次,记录
     */
    private Map<Integer, CrossXiuXianPvpEndRecord> endRecordMap = new ConcurrentHashMap<>();

    private Set<Long> inPvpActivity = new HashSet<>();

    private CrossXiuXianChatLogic chatLogic;

    /**
     * 是否需要同步积分
     */
    private boolean needSyncCampScore = false;

    /**
     *  采集的数据分组
     */
    private List<CrossXiuXianServerScoreData> serverScoreDataList = new ArrayList<>();

    /**
     * 全服公告
     */
    public LinkedList<CrossXiuXianPvpNoticeData> noticeDataList = new LinkedList<>();

    /**
     * 宗门公告
     */
    public Map<Integer, LinkedList<CrossXiuXianPvpNoticeData>> campNoticeDataMap = new ConcurrentHashMap<>();

    /**
     * 宗门房间在线成员：宗门id、灵峰id、房间id、用户id列表
     */
    private Map<Integer, Map<Integer, Map<Integer, Set<Long>>>> inRoomPlayers = new ConcurrentHashMap<>();
    private Map<Long, List<Integer>> userInRoomMap = new ConcurrentHashMap<>();

    /**
     * 历练界面用户, 玩家id
     */

    private Set<Long> practiceUserSet = new HashSet<>();
    /**
     * 房间成员信息:宗门id、灵峰id、房间id、用户id列表
     */
    private Map<Integer, Map<Integer, Map<Integer, List<Long>>>> campMountRoomMap = new ConcurrentHashMap<>();

    /**
     * 同步房间操作
     */
    private Map<Integer, Map<Integer, Map<Integer, List<XiuXianRoomSyncData>>>> changeRoomOpMap = new ConcurrentHashMap<>();
    /**
     * 分配情况
     */
    Map<Long, Map<Long, XiuXianRoomMemberInfo>> allotMap = new ConcurrentHashMap<>();

    /**
     * 分配时间id,分配相关信息
     */
    private Map<Long, CrossXiuXianMountAllotData> mountAllotDataMap = new ConcurrentHashMap<>();

    /**
     * 攻击同步列表      placeId,List
     */
    private Map<Integer, List<CrossXiuXianPvpAttackHelper>> attackSyncListMap = new ConcurrentHashMap<>();

    /**
     * npc攻击开关
     */
    private boolean npcAttack = true;

    /**
     * npc自动复活
     */
    private boolean npcRevive = true;

    /**
     * 玩家锁
     */
    private static final Map<Long, Object> playerLockMap = new ConcurrentHashMap<>();

    /**
     * 房间锁
     */
    private static final Map<Integer, Object> placeLockMap = new ConcurrentHashMap<>();

    /**
     * 获取玩家锁
     */
    private static Object getPlayerLock(long userId) {
        if (!playerLockMap.containsKey(userId)) {
            synchronized (playerLockMap) {
                if (!playerLockMap.containsKey(userId)) {
                    playerLockMap.put(userId, new Object());
                }
            }
        }
        return playerLockMap.get(userId);
    }


    /**
     * 获取房间锁
     */
    private static Object getPlaceLock(int placeId) {
        if (!placeLockMap.containsKey(placeId)) {
            synchronized (placeLockMap) {
                if (!placeLockMap.containsKey(placeId)) {
                    placeLockMap.put(placeId, new Object());
                }
            }
        }
        return placeLockMap.get(placeId);
    }




    public CrossXiuXianActivity(ActivityInfo activityInfo) {
        super(activityInfo);
        // 读数据
        int curRound = getCurRound();
        crossXiuXianPvpData = XiuXianActivityBusiness.getCrossXiuXianPvpData(activityInfo.getActivityId());
        if (crossXiuXianPvpData == null) {
            // 初始化
            crossXiuXianPvpData = new CrossXiuXianPvpData();
            crossXiuXianPvpData.setActivityId(activityInfo.getActivityId());
            crossXiuXianPvpData.setLockState(false);
            crossXiuXianPvpData.setGenCampState(false);
            crossXiuXianPvpData.setRound(curRound);
            crossXiuXianPvpData.setActivityState(eXiuXianPvpActivityStateType.NotStart.getValue());
            crossXiuXianPvpData.setCampScoreRecordMap(new ConcurrentHashMap<>());
            crossXiuXianPvpData.setUpdateTime(System.currentTimeMillis());
            crossXiuXianPvpData.setInsertOption();
        }
        // pvp玩家数据
        pvpUserDataMap = XiuXianActivityBusiness.getCrossXiuXianPvpUserDataMap(activityInfo.getActivityId());
        // pvp阵营数据
        pvpCampDataMap = XiuXianActivityBusiness.getCrossXiuXianPvpCampDataMap(activityInfo.getActivityId());
        // 初始化阵营数据
        initCampData();
        // pvp房间信息
        pvpPlaceDataMap = XiuXianActivityBusiness.getCrossXiuXianPvpPlaceDataMap(activityInfo.getActivityId());
        initPlaceData();
        // 轮次最佳记录
        endRecordMap = XiuXianActivityBusiness.getCrossXiuXianPvpEndRecordMap(activityInfo.getActivityId());
        // 获取本轮全服公告
        int limitNotice = config.getXIUXIAN_PVP_NOTICE_NUM();
        noticeDataList = XiuXianActivityBusiness.getCrossXiuXianPvpNoticeDataList(activityInfo.getActivityId(), curRound, 0, limitNotice);
        Collections.reverse(noticeDataList);
        // 获取本轮宗门公告
        campNoticeDataMap = new ConcurrentHashMap<>();
        for (int campId : pvpCampDataMap.keySet()) {
            LinkedList<CrossXiuXianPvpNoticeData> campNoticeDataList = XiuXianActivityBusiness.getCrossXiuXianPvpNoticeDataList(activityInfo.getActivityId(), curRound, campId, limitNotice);
            Collections.reverse(campNoticeDataList);
            campNoticeDataMap.put(campId, campNoticeDataList);
        }
        // 区服评分采集数据
        serverScoreDataList = XiuXianActivityBusiness.getCrossXiuXianServerScoreDataList(activityInfo.getActivityId());
        // 灵峰分配相关信息
        mountAllotDataMap = XiuXianActivityBusiness.getCrossXiuXianMountAllotDataMap(activityInfo.getActivityId());
        // 初始化榜单
        initAllRankList();

        chatLogic = new CrossXiuXianChatLogic(activityInfo);
    }

    /**
     * 活动是否战斗中
     */
    public boolean isBattleTime() {
        return ActivityHelper.activityInTime(config.getActivityInfo()) &&crossXiuXianPvpData.getActivityState() == eXiuXianPvpActivityStateType.Battle.getValue();
    }

    /**
     * 活动是否开启
     */
    public boolean isOpenTime() {
        return ActivityHelper.activityInTime(config.getActivityInfo()) &&
                (crossXiuXianPvpData.getActivityState() == eXiuXianPvpActivityStateType.Prepare.getValue() ||
                        crossXiuXianPvpData.getActivityState() == eXiuXianPvpActivityStateType.Battle.getValue());
    }



    /**
     * 所有宗门最高积分
     */
    public long getCampMaxScore() {
        long score = 0;
        List<CrossXiuXianPvpCampData> list = new ArrayList<>(pvpCampDataMap.values());
        for (CrossXiuXianPvpCampData campData : list) {
            score = Math.max(campData.getScore(), score);
        }
        return score;
    }

    /**
     * 初始化房间信息
     */
    private void initPlaceData() {
        for (XiuXianPvpPlaceConfig placeConfig : config.getPlaceConfigMap().values()) {
            if (placeConfig == null) {
                continue;
            }
            int placeId = placeConfig.getId();
            synchronized (getPlaceLock(placeId)) {
                if (!pvpPlaceDataMap.containsKey(placeId)) {
                    CrossXiuXianPvpPlaceData pvpPlaceData = new CrossXiuXianPvpPlaceData();
                    pvpPlaceData.setActivityId(config.getActivityInfo().getActivityId());
                    pvpPlaceData.setPlaceId(placeId);
                    pvpPlaceData.setUserList(new HashSet<>());
                    // 初始化阵营占领数据
                    Map<Integer, CrossXiuXianPvpPlaceSeizeInfo> seizeInfoMap = new ConcurrentHashMap<>();
                    for (int campId : pvpCampDataMap.keySet()) {
                        seizeInfoMap.put(campId, new CrossXiuXianPvpPlaceSeizeInfo(campId));
                    }
                    // 固定占领
                    if (placeConfig.getType() != eXiuXianPvpPlaceType.Place.getValue()) {
                        // 宗门
                        pvpPlaceData.setCampId(placeId);
                    }
                    pvpPlaceData.setSeizeInfoMap(seizeInfoMap);
                    long nowTime = System.currentTimeMillis();
                    pvpPlaceData.setUpdateTime(nowTime);
                    pvpPlaceData.setSeizeTime(nowTime);
                    pvpPlaceData.setLastSeizeRewardTime(nowTime);
                    pvpPlaceData.setLastNoticeSeizeTime(nowTime);
                    pvpPlaceData.setInsertOption();
                    pvpPlaceDataMap.put(placeId, pvpPlaceData);
                }
            }
        }
    }

    /**
     * 初始化阵营数据
     */
    public void initCampData() {
        for (int campId = 1; campId <= 4; campId++) {
            if (!pvpCampDataMap.containsKey(campId)) {
                CrossXiuXianPvpCampData campData = new CrossXiuXianPvpCampData();
                campData.setActivityId(config.getActivityInfo().getActivityId());
                campData.setCampId(campId);
                campData.setServerIdList(new HashSet<>());
                campData.setScore(0);
                campData.setTotalScore(0);
                campData.setInsertOption();
                pvpCampDataMap.put(campId, campData);
            }
        }
    }


    /**
     * 获取宝地信息
     *
     * @param placeId 宝地id
     */
    private CrossXiuXianPvpPlaceData getPvpPlace(int placeId) {
        return pvpPlaceDataMap.get(placeId);
    }


    /**
     * 宗门人数是否达到上限
     */
    public boolean checkCampPlayerLimit(int campId, int placeId) {
        XiuXianPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(placeId);
        // 出生点不做拦截，无上限
        if (placeConfig.getType() != eXiuXianPvpPlaceType.Place.getValue()) {
            return false;
        }
        int cnt = 0;
        CrossXiuXianPvpPlaceData placeData = getPvpPlace(placeId);
        if (placeData == null) {
            return true;
        }
        for (Long userId : placeData.getUserList()) {
            CrossXiuXianPvpUserData userData = getPvpUserData(userId);
            if (userData == null || userData.getUserState() == 1) {
                continue;
            }
            if (campId == userData.getCampId()) {
                cnt++;
            }
        }
        return cnt >= config.getXIUXIAN_PVP_ROOM_PEOPLE_NUM_MAX();
    }


    /**
     * 加入到房间中
     *
     * @param placeId     宝地id
     * @param pvpUserData 用户数据
     */
    private void joinPlace(int placeId, CrossXiuXianPvpUserData pvpUserData) {
        if (pvpUserData == null) {
            return;
        }
        long userId = pvpUserData.getUserId();
        // placeId  = 0 为空房间
        if (placeId != 0) {
            synchronized (getPlaceLock(placeId)) {
                // 当前宝地宗门人数
                if (checkCampPlayerLimit(pvpUserData.getCampId(), placeId)) {
                    return;
                }
                // 加入到新房间
                CrossXiuXianPvpPlaceData placeData = getPvpPlace(placeId);
                Set<Long> userList = placeData.getUserList();
                userList.add(userId);
                placeData.setUserList(userList);
                // 检测占领时间
                checkPlaceSeizeTime(placeId, true);
            }
        }
        pvpUserData.setPlaceId(placeId);
        if (placeId != 0) {
            CrossXiuXianPvpPosition position = pvpUserData.getPosition();
            // 随机位置
            // 获取玩家的头像半径
            List<String> radiusList = StringUtils.stringToStringList(config.getXIUXIAN_PVP_PROFILE_RADIUS(), "\\|");
            int radius = 0;
            for (String radiusParam : radiusList) {
                String[] split = radiusParam.split(";");
                long configAbility = Long.parseLong(split[0]);
                if (pvpUserData.getPvpProperty().getStateId() >= configAbility) {
                    radius = Integer.parseInt(split[1]);
                }
            }
            // 房间半径
            XiuXianPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(placeId);
            int placeRadius = placeConfig.getRadius();
            // 玩家位置半径
            int positionRadius = 0;
            if (radius > placeRadius) {
                positionRadius = placeRadius;
            } else {
                positionRadius = placeRadius - radius;
            }
            // 回复活点随机圆内位置
            if (placeConfig.getType() != eXiuXianPvpPlaceType.Place.getValue() || isNpc(userId)) {
                positionRadius = randomHelper.next(0, positionRadius + 1);
            }
            // 随机一个角度
            int angdeg = randomHelper.next(0, 360);
            double x1 = 1125 + positionRadius * Math.cos(Math.toRadians(angdeg));
            double y1 = 900 + positionRadius * Math.sin(Math.toRadians(angdeg));
            position.setX(String.valueOf(x1));
            position.setY(String.valueOf(y1));
            position.setDirX("0");
            position.setDirY("0");
            position.setTime(System.currentTimeMillis());
            // 通知
            XiuXianProto.XiuXianEnterPlaceSync.Builder syncMsg = XiuXianProto.XiuXianEnterPlaceSync.newBuilder();
            syncMsg.setUser(parseXiuXianPvpOtherUserTemp(pvpUserData));
            CrossXiuXianPvpPlaceData placeData = getPvpPlace(placeId);
            sendPacketToAll(Protocol.U_XIU_XIAN_ENTER_PLACE_SYNC, syncMsg, placeData.getUserList());
        }
    }

    /**
     * 离开房间
     */
    public void leavePlace(CrossXiuXianPvpUserData pvpUserData, int type) {
        if (pvpUserData == null) {
            return;
        }
        long userId = pvpUserData.getUserId();
        int placeId = pvpUserData.getPlaceId();
        if (placeId == 0) {
            return;
        }
        // 游离状态
        pvpUserData.setPlaceId(0);
        // 需要通知房间内的用户
        Set<Long> notifyUserList;
        synchronized (getPlaceLock(placeId)) {
            // 从旧的房间移除
            CrossXiuXianPvpPlaceData placeData = getPvpPlace(placeId);
            Set<Long> userList = placeData.getUserList();
            userList.remove(userId);
            placeData.setUserList(userList);
            notifyUserList = placeData.getUserList();
            // 检测占领时间
            checkPlaceSeizeTime(placeId, true);
        }
        // 通知
        XiuXianProto.XiuXianLeavePlaceSync.Builder syncMsg = XiuXianProto.XiuXianLeavePlaceSync.newBuilder();
        syncMsg.setUserId(userId);
        syncMsg.setType(type);
        sendPacketToAll(Protocol.U_XIU_XIAN_LEAVE_PLACE_SYNC, syncMsg, notifyUserList);
    }

    /**
     * 移除npc
     */
    private void removeNpc(long userId) {
        if (!isNpc(userId)) {
            return;
        }
        npcUserMap.remove(userId);
        npcDataMap.remove(userId);
    }

    /**
     * 获取宝地上可占领的阵营id
     *
     * @param place 宝地
     */
    public int getSeizeCampIdInPlace(CrossXiuXianPvpPlaceData place) {
        int campId = 0;
        Map<Integer, Integer> campPlayerCnt = new ConcurrentHashMap<>();
        for (Long userId : place.getUserList()) {
            CrossXiuXianPvpUserData pvpUserData = getPvpUserData(userId);
            if (pvpUserData == null || pvpUserData.getUserState() == 1) {
                continue;
            }
            campPlayerCnt.put(pvpUserData.getCampId(), campPlayerCnt.getOrDefault(pvpUserData.getCampId(), 0) + 1);
        }
        int maxCnt = campPlayerCnt.values().stream().mapToInt(entry -> entry).max().orElse(Integer.MIN_VALUE);
        // 可占领的宗门
        List<Integer> canSeizeCampList = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : campPlayerCnt.entrySet()) {
            if (entry.getValue() == maxCnt) {
                canSeizeCampList.add(entry.getKey());
            }
        }
        // 人数相等不可占领，仅有canSeizeCampList数量为1时可占领
        if (canSeizeCampList.size() == 1) {
            campId = canSeizeCampList.get(0);
        } else if (canSeizeCampList.size() > 1) {
            if (canSeizeCampList.contains(place.getCampId())) {
                campId = place.getCampId();
            } else if (canSeizeCampList.contains(place.getLastSeizeCampId())) {
                campId = place.getLastSeizeCampId();
            }
        }
        if (campId != 0) {
            place.setLastSeizeCampId(campId);
        }
        return campId;
    }

    /**
     * 计算抢占产出
     *
     * @param place 宝地
     */
    private long seizeProduce(CrossXiuXianPvpPlaceData place) {
        long nowTime = System.currentTimeMillis();
        XiuXianPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(place.getPlaceId());
        if (placeConfig == null) {
            return 0;
        }
        long produceTime = (nowTime - place.getLastSeizeRewardTime()) / 1000;
        place.setLastSeizeRewardTime(nowTime);
        return produceTime * placeConfig.getSeizeProduce();
    }

    /**
     * 检测占领时间
     *
     * @param placeId 宝地id
     */
    private void checkPlaceSeizeTime(int placeId, boolean needSync) {
        boolean isSeize = false;
        // 上一次占领的时间
        long lastTotalTime = 0;
        // 产出了多少
        long lastSeizeScore = 0;
        // 抢占成功 需要增加占点战绩的人
        List<Long> needAddScoreUserList = new ArrayList<>();
        int seizeCampId = 0;
        int campId = 0;
        XiuXianPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(placeId);
        if (placeConfig == null) {
            return;
        }
        synchronized (getPlaceLock(placeId)) {
            CrossXiuXianPvpPlaceData placeData = getPvpPlace(placeId);
            if (placeData == null) {
                return;
            }
            // 活动进行中才处理
            if (!isBattleTime()) {
                return;
            }
            long nowTime = System.currentTimeMillis();
            // 获取当前可占领的宗门id
            seizeCampId = getSeizeCampIdInPlace(placeData);
            // 当前占领的宗门
            campId = placeData.getCampId();
            // 只处理宝地
            if (placeConfig.getType() != eXiuXianPvpPlaceType.Place.getValue()) {
                return;
            }
            for (CrossXiuXianPvpPlaceSeizeInfo seizeInfo : placeData.getSeizeInfoMap().values()) {
                if (seizeCampId == placeData.getCampId()) {
                    continue;
                }
                // 未占领的判断下
                if (seizeInfo.getCampId() != seizeCampId) {
                    continue;
                }
                if (isSeize) {
                    break;
                }
                int offsetTime = Math.max(0, (int) (nowTime - Math.max(config.getPvpStartTime(), placeData.getUpdateTime())));
                // 累计计时
                seizeInfo.setSeizeTime(seizeInfo.getSeizeTime() + offsetTime);
                // 抢占成功
                if (seizeInfo.getSeizeTime() >= config.getXIUXIAN_PVP_SEIZE_COUNT_TIME() * DateHelper.SECOND_MILLIONS) {
                    lastTotalTime = (nowTime - placeData.getSeizeTime()) / 1000;
                    lastSeizeScore = (nowTime - placeData.getSeizeTime()) / 1000 * placeConfig.getSeizeProduce();
                    placeData.setCampId(seizeInfo.getCampId());
                    placeData.setSeizeTime(nowTime);
                    placeData.setLastNoticeSeizeTime(nowTime);
                    placeData.setLastSeizeRewardTime(nowTime);
                    // 抢占得分
                    addCampScore(placeData.getCampId(), placeConfig.getSeizeScore());
                    // 当前宗门的人增加抢占战绩
                    Set<Long> userList = placeData.getUserList();
                    for (Long userId : userList) {
                        CrossXiuXianPvpUserData pvpUserData = getPvpUserData(userId);
                        if (pvpUserData == null || pvpUserData.getUserState() == 1 || isNpc(pvpUserData.getUserId()) || pvpUserData.getCampId() != seizeInfo.getCampId()) {
                            continue;
                        }
                        needAddScoreUserList.add(userId);
                    }
                    isSeize = true;
                }
            }
            // 成功占领,其他全部清0
            if (isSeize) {
                for (CrossXiuXianPvpPlaceSeizeInfo seizeInfo : placeData.getSeizeInfoMap().values()) {
                    seizeInfo.setSeizeTime(0);
                }
                needSync = true;
            }
            placeData.setUpdateTime(nowTime);
            if (needSync) {
                // 同步房间抢占数据
                syncXiuXianPlaceSeizeMsg(placeData, seizeCampId);
            }
        }
        if (isSeize) {
            CrossXiuXianPvpPlaceData placeData = getPvpPlace(placeId);
            if (campId != 0) {
                // 添加公告
                CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
                noticeData.setActivityId(config.getActivityInfo().getActivityId());
                noticeData.setRound(getCurRound());
                noticeData.setCampId(campId);
                noticeData.setNoticeType(eXiuXianPvpNoticeType.LosePlace.getValue());
                noticeData.setContent(placeId + "#" + placeData.getCampId());
                noticeData.setNoticeTime(System.currentTimeMillis());
                noticeData.setIsRoll(Integer.parseInt(config.getXIUXIAN_PVP_NOTICE_PLACE_CHANGED_HANDS()));
                addPvpNoticeData(noticeData, 0, 0);
            }
            // 被抢占日志
            CrossAutoLogMgr.add(new LogXiuXianPvpPlaceSeize(
                    config.getActivityInfo().getActivityId(),
                    campId,
                    getCurRound(),
                    placeId,
                    1,
                    new Date(),
                    lastTotalTime,
                    lastSeizeScore
            ));
            for (Long userId : needAddScoreUserList) {
                CrossXiuXianPvpUserData userData;
                synchronized (getPlayerLock(userId)){
                    userData = getPvpUserData(userId);
                    if (userData == null) {
                        continue;
                    }
                    // 占领战绩
                    List<Integer> scoreList = StringUtils.stringToIntegerList(config.getXIUXIAN_PVP_PERSONAL_SCORE_SEIZE(), "\\|");
                    long addSeizeScore = 0;
                    if (scoreList.size() > 0) {
                        addSeizeScore = scoreList.get(Math.min(placeConfig.getLevel() - 1, scoreList.size() - 1));
                    }
                    addBattleScore(userId, 2, addSeizeScore, "");
                    // 加一下参与抢占的地点
                    CrossXiuXianPvpBattleRecord battleRecord = userData.getBattleRecord();
                    battleRecord.getSeizePlace().add(placeId);
                    userData.setBattleRecord(battleRecord);
                }
                // 判断下抢占是否满足本轮推送公告
                List<String> noticeParamList = StringUtils.stringToStringList(config.getXIUXIAN_PVP_NOTICE_SINGLE_WHEEL_SEIZE_NUM(), "\\|");
                String params = noticeParamList.get(1);
                List<Integer> paramList = StringUtils.stringToIntegerList(params, ";");
                int curRound = getCurRound();
                int seizeNum = 0;
                if (userData.getBattleRecordMap().containsKey(curRound)) {
                    seizeNum = userData.getBattleRecordMap().get(curRound).getSeize();
                }
                if (paramList.contains(seizeNum)) {
                    // 添加公告
                    CrossXiuXianPvpNoticeData noticeData1 = new CrossXiuXianPvpNoticeData();
                    noticeData1.setActivityId(config.getActivityInfo().getActivityId());
                    noticeData1.setRound(curRound);
                    noticeData1.setCampId(userData.getCampId());
                    noticeData1.setNoticeType(eXiuXianPvpNoticeType.TotalSeize.getValue());
                    noticeData1.setContent(String.valueOf(seizeNum));
                    noticeData1.setNoticeTime(System.currentTimeMillis());
                    noticeData1.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
                    addPvpNoticeData(noticeData1, userData.getUserId(), 0);
                }
            }
            // 宝地抢占推送
            List<String> noticeParamList = StringUtils.stringToStringList(config.getXIUXIAN_PVP_NOTICE_PLACE_LEVEL(), "\\|");
            String params = noticeParamList.get(1);
            List<Integer> paramList = StringUtils.stringToIntegerList(params, ";");
            if (paramList.contains(placeConfig.getLevel())) {
                // 添加公告
                CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
                noticeData.setActivityId(config.getActivityInfo().getActivityId());
                noticeData.setRound(getCurRound());
                noticeData.setCampId(seizeCampId);
                noticeData.setNoticeType(eXiuXianPvpNoticeType.SeizePlace.getValue());
                noticeData.setContent(String.valueOf(placeId));
                noticeData.setNoticeTime(System.currentTimeMillis());
                noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
                addPvpNoticeData(noticeData, 0, 0);
            }
        }
    }

    /**
     * 增加宗门积分
     *
     * @param campId   宗门id
     * @param addScore 增加积分
     */
    public void addCampScore(int campId, long addScore) {
        if (addScore == 0) {
            return;
        }
        long oldScore = 0;
        long newScore = 0;
        synchronized (lock) {
            CrossXiuXianPvpCampData campData = getPvpCampData(campId);
            if (campData == null) {
                return;
            }
            oldScore = campData.getScore();
            campData.setScore(campData.getScore() + addScore);
            campData.setTotalScore(campData.getTotalScore() + addScore);
            campData.setUpdateScoreTime(System.currentTimeMillis());
            newScore = campData.getScore();
            // 本轮积分榜
            campScoreRankMap.rankChange(new CrossXiuXianRank(String.valueOf(campData.getCampId()), campData.getScore(), campData.getUpdateScoreTime()));
            // 活动总积分榜
            campTotalScoreRankMap.rankChange(new CrossXiuXianRank(String.valueOf(campData.getCampId()), campData.getTotalScore(), campData.getUpdateScoreTime()));
            needSyncCampScore = true;
            // 更新下积分
            int curRound = getCurRound();
            Map<Integer, Map<Integer, CrossXiuXianPvpCampScoreRecord>> campScoreRecordMap = crossXiuXianPvpData.getCampScoreRecordMap();
            Map<Integer, CrossXiuXianPvpCampScoreRecord> recordMap = campScoreRecordMap.getOrDefault(curRound, new ConcurrentHashMap<>());
            int rankNum = 0;
            for (CrossXiuXianRank rank : campScoreRankMap.getRankList()) {
                ++rankNum;
                int tempCampId = Integer.parseInt(rank.getId());
                CrossXiuXianPvpCampScoreRecord record = recordMap.getOrDefault(tempCampId, new CrossXiuXianPvpCampScoreRecord());
                record.setCampId(tempCampId);
                record.setScore(rank.getValue());
                record.setRank(rankNum);
                recordMap.put(tempCampId, record);
            }
            campScoreRecordMap.put(curRound, recordMap);
            crossXiuXianPvpData.setCampScoreRecordMap(campScoreRecordMap);
        }
        // 添加公告
        // 检测下结束公告
        List<String> noticeParamList = StringUtils.stringToStringList(config.getXIUXIAN_PVP_NOTICE_BATTLE_END_TIME_SECT_SCORE(), "\\|");
        String params = noticeParamList.get(1);
        List<Integer> paramList = StringUtils.stringToIntegerList(params, ";");
        long oldOffsetScore = config.getPvpBattleTimeEndCondition().get(1) - oldScore;
        long newOffsetScore = config.getPvpBattleTimeEndCondition().get(1) - newScore;
        int canNoticeScore = -1;
        for (int noticeScore : paramList) {
            if (oldOffsetScore > noticeScore && noticeScore >= newOffsetScore) {
                canNoticeScore = noticeScore;
            }
        }
        if (canNoticeScore > 0) {
            // 添加公告
            CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
            noticeData.setActivityId(config.getActivityInfo().getActivityId());
            noticeData.setRound(getCurRound());
            noticeData.setCampId(campId);
            noticeData.setNoticeType(eXiuXianPvpNoticeType.PvpScoreEnd.getValue());
            noticeData.setContent(String.valueOf(canNoticeScore));
            noticeData.setNoticeTime(System.currentTimeMillis());
            noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
            addPvpNoticeData(noticeData, 0, 0);
        }
    }

    /**
     * 斗法结束通知
     */
    public void xiuXianPvpEndSync() {
        // 添加记录
        int curRound = getCurRound();
        if (endRecordMap.containsKey(curRound)) {
            return;
        }
        long nowTime = System.currentTimeMillis();
        CrossXiuXianPvpEndRecord record = new CrossXiuXianPvpEndRecord();
        record.setActivityId(config.getActivityInfo().getActivityId());
        record.setRound(curRound);
        CrossXiuXianPvpBestBattleRecord bestSeizeUser = getBestBattleUser(1, 0);
        if (bestSeizeUser != null) {
            record.setBestSeizeUser(bestSeizeUser);
        }
        CrossXiuXianPvpBestBattleRecord bestKillUser = getBestBattleUser(2, 0);
        if (bestKillUser != null) {
            record.setBestKillUser(bestKillUser);
        }
        // 宗门最佳抢占map
        Map<Integer, CrossXiuXianPvpBestBattleRecord> campBestSeizeUserMap = new ConcurrentHashMap<>();
        // 宗门最佳击杀map
        Map<Integer, CrossXiuXianPvpBestBattleRecord> campBestKillUserMap = new ConcurrentHashMap<>();
        for (int campId : pvpCampDataMap.keySet()) {
            CrossXiuXianPvpBestBattleRecord campBestSeizeUser = new CrossXiuXianPvpBestBattleRecord();
            CrossXiuXianPvpBestBattleRecord tempSeizeUser = getBestBattleUser(1, campId);
            if (tempSeizeUser != null) {
                campBestSeizeUser = tempSeizeUser;
            }
            campBestSeizeUserMap.put(campId, campBestSeizeUser);
            CrossXiuXianPvpBestBattleRecord campBestKillUser = new CrossXiuXianPvpBestBattleRecord();
            CrossXiuXianPvpBestBattleRecord tempKillUser = getBestBattleUser(2, campId);
            if (tempKillUser != null) {
                campBestKillUser = tempKillUser;
            }
            campBestKillUserMap.put(campId, campBestKillUser);
        }
        record.setCampBestSeizeUserMap(campBestSeizeUserMap);
        record.setCampBestKillUserMap(campBestKillUserMap);
        record.setEndTime(nowTime);
        record.setInsertOption();
        endRecordMap.put(curRound, record);

        // 同步活动结束
        XiuXianProto.CrossXiuXianPvpActivityDataSync.Builder builder = XiuXianProto.CrossXiuXianPvpActivityDataSync.newBuilder();
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setRound(getCurRound());
        builder.setState(crossXiuXianPvpData.getActivityState());
        sendPacketToAll(Protocol.S_CROSS_XIU_XIAN_GET_ACTIVITY_DATA, builder, pvpUserDataMap.keySet());

        // 处理下宝地记录
        for (CrossXiuXianPvpPlaceData placeData : pvpPlaceDataMap.values()) {
            XiuXianPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(placeData.getPlaceId());
            // 被抢占日志
            CrossAutoLogMgr.add(new LogXiuXianPvpPlaceSeize(
                    config.getActivityInfo().getActivityId(),
                    placeData.getCampId(),
                    getCurRound(),
                    placeData.getPlaceId(),
                    2,
                    new Date(),
                    (nowTime - placeData.getSeizeTime()) / 1000,
                    (nowTime - placeData.getSeizeTime()) / 1000 * placeConfig.getSeizeProduce()
            ));
        }
    }

    /**
     * 获取最佳用户
     *
     * @param type   1:抢点 2:击杀
     * @param campId 宗门id,0为获取本轮
     */
    public CrossXiuXianPvpBestBattleRecord getBestBattleUser(int type, int campId) {
        // 当前轮次
        int curRound = getCurRound();
        int maxCnt = 0;
        long maxScore = 0;
        long maxUserId = 0;
        CrossXiuXianPvpBattleRecord battleRecord = new CrossXiuXianPvpBattleRecord();
        for (CrossXiuXianPvpUserData userData : pvpUserDataMap.values()) {
            if (!userData.getBattleRecordMap().containsKey(curRound)) {
                continue;
            }
            // 获取宗门的
            if (campId != 0 && userData.getCampId() != campId) {
                continue;
            }
            CrossXiuXianPvpBattleRecord tempRecord = userData.getBattleRecordMap().get(curRound);
            // 对比吧
            if (type == 1) {
                if (tempRecord.getSeize() >= maxCnt) {
                    // 积分相等比较战绩
                    if (tempRecord.getSeize() == maxCnt && tempRecord.getSeizeScore() < maxScore) {
                        continue;
                    }
                    maxCnt = tempRecord.getSeize();
                    maxScore = tempRecord.getSeizeScore();
                    maxUserId = userData.getUserId();
                    battleRecord = tempRecord;
                }
            } else if (type == 2) {
                if (tempRecord.getKill() >= maxCnt) {
                    // 积分相等比较战绩
                    if (tempRecord.getKill() == maxCnt && tempRecord.getKillScore() < maxScore) {
                        continue;
                    }
                    maxCnt = tempRecord.getKill();
                    maxScore = tempRecord.getKillScore();
                    maxUserId = userData.getUserId();
                    battleRecord = tempRecord;
                }
            }
        }
        if (maxUserId == 0) {
            return null;
        }
        CrossXiuXianPvpBestBattleRecord bestBattleRecord = new CrossXiuXianPvpBestBattleRecord();
        bestBattleRecord.setUserId(maxUserId);
        bestBattleRecord.setCampId(getCampByUserId(maxUserId));
        bestBattleRecord.setBattleRecord(battleRecord);
        return bestBattleRecord;
    }


    /**
     * 同步房间抢占数据
     *
     * @param seizeCampId 正在抢占的宗门
     */
    public void syncXiuXianPlaceSeizeMsg(CrossXiuXianPvpPlaceData placeData, int seizeCampId) {
        if (placeData == null) {
            return;
        }
        XiuXianProto.XiuXianPlaceSeizeSyncMsg.Builder builder = XiuXianProto.XiuXianPlaceSeizeSyncMsg.newBuilder();
        builder.setPlaceId(placeData.getPlaceId());
        // 房间阵营人数
        Map<Integer, Integer> campCnt = new ConcurrentHashMap<>();
        Set<Long> userList = placeData.getUserList();
        for (Long pvpUserId : userList) {
            CrossXiuXianPvpUserData userData = getPvpUserData(pvpUserId);
            if (userData == null) {
                continue;
            }
            if (!isBirthPlace(placeData.getPlaceId()) && userData.getUserState() == 1) {
                continue;
            }
            campCnt.put(userData.getCampId(), campCnt.getOrDefault(userData.getCampId(), 0) + 1);
        }
        for (CrossXiuXianPvpPlaceSeizeInfo seizeInfo : placeData.getSeizeInfoMap().values()) {
            builder.addSeize(parseXiuXianPvpPlaceSeizeInfoTemp(seizeInfo, campCnt));
        }
        builder.setBeginTime(System.currentTimeMillis());
        if (seizeCampId == placeData.getCampId()) {
            seizeCampId = 0;
        }
        builder.setSeizeCampId(seizeCampId);
        builder.setSeizeTime(placeData.getSeizeTime());
        builder.setCampId(placeData.getCampId());
        sendPacketToAll(Protocol.U_XIU_XIAN_PLACE_SEIZE_SYNC, builder, userList);
    }

    public void reloadConfig() {
        loadConfigFromDb(config.getActivityInfo());
    }

    public void save() {
        // 保存活动数据
        if (crossXiuXianPvpData != null) {
            if (crossXiuXianPvpData.isInsertOption()) {
                XiuXianActivityBusiness.addCrossXiuXianPvpData(crossXiuXianPvpData);
            } else if (crossXiuXianPvpData.isUpdateOption()) {
                XiuXianActivityBusiness.updateCrossXiuXianPvpData(crossXiuXianPvpData);
            }
        }
        // 保存用户数据
        for (CrossXiuXianPvpUserData pvpUserData : pvpUserDataMap.values()) {
            if (pvpUserData.isInsertOption()) {
                XiuXianActivityBusiness.addCrossXiuXianPvpUserData(pvpUserData);
            } else if (pvpUserData.isUpdateOption()) {
                XiuXianActivityBusiness.updateCrossXiuXianPvpUserData(pvpUserData);
            }
        }
        // 保存宗门数据
        for (CrossXiuXianPvpCampData pvpCampData : pvpCampDataMap.values()) {
            if (pvpCampData.isInsertOption()) {
                XiuXianActivityBusiness.addCrossXiuXianPvpCampData(pvpCampData);
            } else if (pvpCampData.isUpdateOption()) {
                XiuXianActivityBusiness.updateCrossXiuXianPvpCampData(pvpCampData);
            }
        }
        // 保存宝地数据
        for (CrossXiuXianPvpPlaceData pvpPlaceData : pvpPlaceDataMap.values()) {
            if (pvpPlaceData.isInsertOption()) {
                XiuXianActivityBusiness.addCrossXiuXianPvpPlaceData(pvpPlaceData);
            } else if (pvpPlaceData.isUpdateOption()) {
                XiuXianActivityBusiness.updateCrossXiuXianPvpPlaceData(pvpPlaceData);
            }
        }
        // 保存记录
        for (CrossXiuXianPvpEndRecord endRecord : endRecordMap.values()) {
            if (endRecord.isInsertOption()) {
                XiuXianActivityBusiness.addCrossXiuXianPvpEndRecord(endRecord);
            } else if (endRecord.isUpdateOption()) {
                XiuXianActivityBusiness.updateCrossXiuXianPvpEndRecord(endRecord);
            }
        }
        // 保存记录
        LinkedList<CrossXiuXianPvpNoticeData> tempNoticeDataList = new LinkedList<>(noticeDataList);
        for (CrossXiuXianPvpNoticeData noticeData : tempNoticeDataList) {
            if (noticeData.isInsertOption()) {
                XiuXianActivityBusiness.addCrossXiuXianPvpNoticeData(noticeData);
            }
        }
        List<LinkedList<CrossXiuXianPvpNoticeData>> tempCampNoticeDataList = new ArrayList<>(campNoticeDataMap.values());
        for (LinkedList<CrossXiuXianPvpNoticeData> linkedList : tempCampNoticeDataList) {
            for (CrossXiuXianPvpNoticeData noticeData : linkedList) {
                if (noticeData.isInsertOption()) {
                    XiuXianActivityBusiness.addCrossXiuXianPvpNoticeData(noticeData);
                }
            }
        }

        // 保存数据
        int serverScoreDataListSize = serverScoreDataList.size();
        for (int i = 0; i < serverScoreDataListSize; i++) {
            CrossXiuXianServerScoreData serverScoreData = serverScoreDataList.get(i);
            if (serverScoreData.isInsertOption()) {
                XiuXianActivityBusiness.addCrossXiuXianServerScoreData(serverScoreData);
            } else if (serverScoreData.isUpdateOption()) {
                XiuXianActivityBusiness.updateCrossXiuXianServerScoreData(serverScoreData);
            }
        }

        // 保存数据
        for (CrossXiuXianMountAllotData mountAllotData : mountAllotDataMap.values()) {
            if (mountAllotData.isInsertOption()) {
                XiuXianActivityBusiness.addCrossXiuXianMountAllotData(mountAllotData);
            } else if (mountAllotData.isUpdateOption()) {
                XiuXianActivityBusiness.updateCrossXiuXianMountAllotData(mountAllotData);
            }
        }
    }

    /**
     * 获取仙力宗主
     */
    public int getMajorUserByCmd(long userId) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        // 获取阵营
        int campId = userData.getCampId();
        XiuXianProto.XiuXianGetMajorUserRespMsg.Builder respMsg = XiuXianProto.XiuXianGetMajorUserRespMsg.newBuilder();
        respMsg.setRet(0);
        CrossXiuXianPvpCampData campData = getPvpCampData(campId);
        if (campData != null) {
            // 获取宗主信息
            long majorUserId = campData.getMajorUserId();
            if (majorUserId == 0) {
                // 如果没有宗主则获取宗门最高仙力的人
                majorUserId = getCampMaxAbilityUserId(campId);
            }
            CrossXiuXianPvpUserData pvpUserData = getPvpUserData(majorUserId);
            if (pvpUserData != null) {
                // 这边获取实时的pve属性
                respMsg.setMajorUser(parseXiuXianPveUserDetailTemp(pvpUserData));
            }
        }
        // 获取一下当前的个人阵营排名
        respMsg.setMyRank(getCampUserRankByUserId(userId));
        sendPacket(ClientProtocol.U_XIU_XIAN_GET_MAJOR_USER, respMsg, userId);
        return 0;
    }

    /**
     * 获取阵营区服列表
     */
    public int getCampServerByCmd(long userId) {
        XiuXianProto.XiuXianGetCampServerRespMsg.Builder respMsg = XiuXianProto.XiuXianGetCampServerRespMsg.newBuilder();
        for (CrossXiuXianPvpCampData campData : pvpCampDataMap.values()) {
            XiuXianProto.XiuXianCampServerTemp.Builder camp = XiuXianProto.XiuXianCampServerTemp.newBuilder();
            for (long serverId : campData.getServerIdList()) {
                camp.addServerId(serverId);
            }
            camp.setCampId(campData.getCampId());
            respMsg.addCamp(camp);
        }
        respMsg.setRet(0);
        sendPacket(ClientProtocol.U_XIU_XIAN_GET_CAMP_SERVER, respMsg, userId);
        return 0;
    }

    /**
     * 获取pvp战报
     */
    public int getPvpReportByCmd(long userId, long targetUserId) {
        XiuXianProto.XiuXianGetPvpReportRespMsg.Builder respMsg = XiuXianProto.XiuXianGetPvpReportRespMsg.newBuilder();
        // 获取pvp战报
        // 个人战报
        CrossXiuXianPvpUserData userData = getPvpUserData(targetUserId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        int curRound = getCurRound();
        Map<Integer, CrossXiuXianPvpBattleRecord> battleRecordMap = new HashMap<>(userData.getBattleRecordMap());
        if (isAble(targetUserId) && !battleRecordMap.containsKey(curRound)) {
            // 有资格的本轮也生成一份
            battleRecordMap.put(curRound, new CrossXiuXianPvpBattleRecord());
        }
        for (Map.Entry<Integer, CrossXiuXianPvpBattleRecord> entry : battleRecordMap.entrySet()) {
            XiuXianProto.XiuXianPersonReportTemp.Builder builder = XiuXianProto.XiuXianPersonReportTemp.newBuilder();
            builder.setKill(entry.getValue().getKill());
            builder.setKillScore(entry.getValue().getKillScore());
            builder.setSeize(entry.getValue().getSeize());
            builder.setSeizeScore(entry.getValue().getSeizeScore());
            builder.setRound(entry.getKey());
            respMsg.addPerson(builder);
        }
        // 宗门战报
        HashMap<Integer, Map<Integer, CrossXiuXianPvpCampScoreRecord>> campScoreRecordMap = new HashMap<>(crossXiuXianPvpData.getCampScoreRecordMap());
        // 本轮也生成一份
        if (!campScoreRecordMap.containsKey(curRound)) {
            Map<Integer, CrossXiuXianPvpCampScoreRecord> recordMap = new HashMap<>();
            int rank = 1;
            for (int campId : pvpCampDataMap.keySet()) {
                CrossXiuXianPvpCampScoreRecord record = new CrossXiuXianPvpCampScoreRecord();
                record.setCampId(campId);
                record.setScore(0);
                record.setRank(rank++);
                recordMap.put(campId, record);
            }
            campScoreRecordMap.put(curRound, recordMap);
        }
        for (Map.Entry<Integer, Map<Integer, CrossXiuXianPvpCampScoreRecord>> recordMap : campScoreRecordMap.entrySet()) {
            XiuXianProto.XiuXianCampReportTemp.Builder builder = XiuXianProto.XiuXianCampReportTemp.newBuilder();
            for (Map.Entry<Integer, CrossXiuXianPvpCampScoreRecord> entry : recordMap.getValue().entrySet()) {
                XiuXianProto.XiuXianCampScoreReportTemp.Builder report = XiuXianProto.XiuXianCampScoreReportTemp.newBuilder();
                report.setCampId(entry.getValue().getCampId());
                report.setScore(entry.getValue().getScore());
                report.setRank(entry.getValue().getRank());
                builder.addCamp(report);
            }
            builder.setRound(recordMap.getKey());
            respMsg.addCamp(builder);
        }
        respMsg.setRet(0);
        sendPacket(ClientProtocol.U_XIU_XIAN_GET_PVP_REPORT, respMsg, userId);
        return 0;
    }

    /**
     * 标记地点
     */
    public int markPlaceByCmd(long userId, int placeId) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        if (!pvpPlaceDataMap.containsKey(placeId)) {
            return GameErrorCode.E_XIU_XIAN_PVP_PLACE_NOT_FOUND;
        }
        // 阵营id
        int campId = userData.getCampId();
        // 阵营信息
        CrossXiuXianPvpCampData campData = getPvpCampData(campId);
        if (userId != campData.getMajorUserId() && userId != campData.getMinorUserId()) {
            return GameErrorCode.E_XIU_XIAN_PVP_DONT_MARK_PLACE;
        }
        // 宗主标记
        long nowTime = System.currentTimeMillis();
        // 标记cd
        int markCd = config.getXIUXIAN_PVP_SIGN_CD();
        if (userId == campData.getMajorUserId()) {
            if (placeId == campData.getMajorPlaceId()) {
                campData.setMajorPlaceId(0);
            } else {
                if (nowTime < campData.getMajorMarkTime()) {
                    return GameErrorCode.E_XIU_XIAN_PVP_MARK_TIME_NO_ENOUGH;
                }
                campData.setMajorPlaceId(placeId);
                // 设置下次可标记的时间
                campData.setMajorMarkTime(nowTime + DateHelper.SECOND_MILLIONS * markCd);
                // 添加公告
                CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
                noticeData.setActivityId(config.getActivityInfo().getActivityId());
                noticeData.setRound(getCurRound());
                noticeData.setCampId(campId);
                noticeData.setNoticeType(eXiuXianPvpNoticeType.MajorMarkPlace.getValue());
                noticeData.setContent(String.valueOf(placeId));
                noticeData.setNoticeTime(System.currentTimeMillis());
                noticeData.setIsRoll(Integer.parseInt(config.getXIUXIAN_PVP_NOTICE_SIGN()));
                addPvpNoticeData(noticeData, userId, 0);
            }
        }
        // 副宗主标记
        if (userId == campData.getMinorUserId()) {
            if (placeId == campData.getMinorPlaceId()) {
                campData.setMinorPlaceId(0);
            } else {
                if (nowTime < campData.getMinorMarkTime()) {
                    return GameErrorCode.E_XIU_XIAN_PVP_MARK_TIME_NO_ENOUGH;
                }
                campData.setMinorPlaceId(placeId);
                // 设置下次可标记的时间
                campData.setMinorMarkTime(nowTime + DateHelper.SECOND_MILLIONS * markCd);
                // 添加公告
                CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
                noticeData.setActivityId(config.getActivityInfo().getActivityId());
                noticeData.setRound(getCurRound());
                noticeData.setCampId(campId);
                noticeData.setNoticeType(eXiuXianPvpNoticeType.MinorMarkPlace.getValue());
                noticeData.setContent(String.valueOf(placeId));
                noticeData.setNoticeTime(System.currentTimeMillis());
                noticeData.setIsRoll(Integer.parseInt(config.getXIUXIAN_PVP_NOTICE_SIGN()));
                addPvpNoticeData(noticeData, userId, 0);
            }
        }
        XiuXianProto.XiuXianMarkPlaceRespMsg.Builder respMsg = XiuXianProto.XiuXianMarkPlaceRespMsg.newBuilder();
        respMsg.setRet(0);
        sendPacket(ClientProtocol.U_XIU_XIAN_MARK_PLACE, respMsg, userId);
        // 同步宗门信息到本宗门的成员
        syncCampInfoToAllCampMember(campId);
        return 0;
    }


    /**
     * 获取本阵营玩家信息
     */
    public int getCampUserListByCmd(long userId) {
        CrossXiuXianPvpUserData pvpUserData = getPvpUserData(userId);
        if (pvpUserData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        // 阵营id
        int campId = pvpUserData.getCampId();
        XiuXianProto.XiuXianGetCampUserListRespMsg.Builder respMsg = XiuXianProto.XiuXianGetCampUserListRespMsg.newBuilder();
        // 获取本阵营玩家信息
        for (CrossXiuXianPvpUserData userData : pvpUserDataMap.values()) {
            if (isAble(userData.getUserId()) && userData.getCampId() == campId) {
                XiuXianProto.XiuXianPvpUserDetailTemp.Builder userDetailTemp = parseXiuXianPvpUserDetailTemp(userData);
                if (userDetailTemp != null) {
                    respMsg.addUser(userDetailTemp);
                }
            }
        }
        respMsg.setRet(0);
        sendPacket(ClientProtocol.U_XIU_XIAN_GET_CAMP_USER_LIST, respMsg, userId);
        return 0;
    }

    /**
     * 任命副宗主
     * minorUserId 为 0 移除副宗主
     */
    public int appointMinorUserByCmd(long userId, long minorUserId) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        // 宗门id
        int campId = userData.getCampId();
        CrossXiuXianPvpCampData campData = getPvpCampData(campId);
        if (campData.getMajorUserId() != userId) {
            return GameErrorCode.E_XIU_XIAN_PVP_NO_PERMISSION;
        }
        XiuXianProto.XiuXianAppointMinorUserRespMsg.Builder respMsg = XiuXianProto.XiuXianAppointMinorUserRespMsg.newBuilder();
        if (minorUserId == 0) {
            // 移除副宗主相关操作
            campData.setMinorPlaceId(0);
            campData.setMinorMarkTime(0);
            // 添加公告
            CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
            noticeData.setActivityId(config.getActivityInfo().getActivityId());
            noticeData.setRound(getCurRound());
            noticeData.setCampId(campId);
            noticeData.setNoticeType(eXiuXianPvpNoticeType.CancelAppoint.getValue());
            noticeData.setContent("");
            noticeData.setNoticeTime(System.currentTimeMillis());
            noticeData.setIsRoll(Integer.parseInt(config.getXIUXIAN_PVP_NOTICE_APPOINTMENT_RECOVERY()));
            addPvpNoticeData(noticeData, userId, campData.getMinorUserId());

        } else {
            // 任命操作需要限制
            CrossXiuXianPvpUserData minorUser = getPvpUserData(minorUserId);
            if (minorUser == null) {
                return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
            }
            if (minorUser.getCampId() != campId) {
                return GameErrorCode.E_XIU_XIAN_PVP_ONLY_APPOINT_THE_SAME_CAMP;
            }
            long nowTime = System.currentTimeMillis();
            if (nowTime < campData.getAppointTime()) {
                return GameErrorCode.E_XIU_XIAN_PVP_APPOINT_TIME_LIMIT;
            }
            // 任命cd
            campData.setAppointTime(nowTime + DateHelper.SECOND_MILLIONS * config.getXIUXIAN_PVP_APPOINTMENT_CD());
            // 添加公告
            CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
            noticeData.setActivityId(config.getActivityInfo().getActivityId());
            noticeData.setRound(getCurRound());
            noticeData.setCampId(campId);
            noticeData.setNoticeType(eXiuXianPvpNoticeType.Appoint.getValue());
            noticeData.setContent("");
            noticeData.setNoticeTime(System.currentTimeMillis());
            noticeData.setIsRoll(Integer.parseInt(config.getXIUXIAN_PVP_NOTICE_APPOINTMENT()));
            addPvpNoticeData(noticeData, userId, minorUserId);
        }
        campData.setMinorUserId(minorUserId);
        respMsg.setRet(0);
        sendPacket(ClientProtocol.U_XIU_XIAN_APPOINT_MINOR_USER, respMsg, userId);
        // 同步下数据给宗门成员
        syncCampInfoToAllCampMember(campId);
        return 0;
    }

    /**
     * 获取用户的阵营
     */
    public int getCampByUserId(long userId) {
        CrossXiuXianPvpUserData pvpUserData = getPvpUserData(userId);
        if (pvpUserData == null) {
            return 0;
        }
        return pvpUserData.getCampId();
    }

    public boolean isBirthPlace(int placeId) {
        XiuXianPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(placeId);
        if (placeConfig == null) {
            return false;
        }
        return placeConfig.getType() != eXiuXianPvpPlaceType.Place.getValue();
    }

    /**
     * 获取房间信息
     */
    public int getPlaceInfoByCmd(long userId) {
        XiuXianProto.XiuXianGetPlaceInfoRespMsg.Builder respMsg = XiuXianProto.XiuXianGetPlaceInfoRespMsg.newBuilder();
        List<CrossXiuXianPvpPlaceData> list = new ArrayList<>(pvpPlaceDataMap.values());
        for (CrossXiuXianPvpPlaceData placeData : list) {
            XiuXianProto.XiuXianPvpPlaceSimpleTemp.Builder place = XiuXianProto.XiuXianPvpPlaceSimpleTemp.newBuilder();
            place.setPlaceId(placeData.getPlaceId());
            place.setSeizeCampId(placeData.getCampId());
            // 阵营人数
            Map<Integer, Integer> campCnt = new ConcurrentHashMap<>();
            for (Long pvpUserId : placeData.getUserList()) {
                CrossXiuXianPvpUserData userData = getPvpUserData(pvpUserId);
                if (userData == null) {
                    continue;
                }
                // 出生地等待复活的也显示
                if (!isBirthPlace(place.getPlaceId()) && userData.getUserState() == 1) {
                    continue;
                }
                campCnt.put(userData.getCampId(), campCnt.getOrDefault(userData.getCampId(), 0) + 1);
            }
            for (Map.Entry<Integer, Integer> entry : campCnt.entrySet()) {
                // 阵营0的话就不加进去了
                if (entry.getKey() == 0 || entry.getValue() == 0) {
                    continue;
                }
                XiuXianProto.XiuXianPlaceCampMemberTemp.Builder member = XiuXianProto.XiuXianPlaceCampMemberTemp.newBuilder();
                member.setCampId(entry.getKey());
                member.setNum(entry.getValue());
                place.addCampMember(member);
            }
            respMsg.addPlace(place);
        }
        respMsg.setRet(0);
        sendPacket(ClientProtocol.U_XIU_XIAN_GET_PLACE_INFO, respMsg, userId);
        return 0;
    }

    /**
     * 获取阵营最高的仙力玩家id
     */
    public long getCampMaxAbilityUserId(int campId) {
        long userId = 0;
        CrossXiuXianRankListModel rankListModel = campUserRankMap.get(campId);
        if (rankListModel != null) {
            LinkedList<CrossXiuXianRank> rankLinkedList = rankListModel.getRankList();
            if (!rankLinkedList.isEmpty()) {
                CrossXiuXianRank first = rankLinkedList.getFirst();
                userId = Long.parseLong(first.getId());
            }
        }
        return userId;
    }

    /**
     * 获取宗门排名
     */
    public int getCampUserRankByUserId(long userId) {
        int rankNum = -1;
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return rankNum;
        }
        int campId = userData.getCampId();
        CrossXiuXianRankListModel rankListModel = campUserRankMap.get(campId);
        if (rankListModel != null) {
            LinkedList<CrossXiuXianRank> rankLinkedList = rankListModel.getRankList();
            int num = 0;
            for (CrossXiuXianRank rank : rankLinkedList) {
                num++;
                if (Long.parseLong(rank.getId()) == userId) {
                    rankNum = num;
                    break;
                }
            }
        }
        return rankNum;
    }

    /**
     * 用户数据更新
     */
    public void pvePropertyChange(XiuXianProto.CrossXiuXianPvePropertyChangeReqMsg temp) {
        CrossXiuXianPvpUserData userData = getPvpUserData(temp.getUserId());
        if (userData != null) {
            // 更新属性
            XiuXianPveUserProperty property = parseXiuXianUserPveProperty(temp.getPveProperty());
            // 境界或者仙力变更才更新
            if (userData.getPveProperty().getStateId() != property.getStateId() || userData.getPveProperty().getPowerVal() != property.getPowerVal()) {
                userData.setUpdatePropertyTime(System.currentTimeMillis());
            }
            userData.setPveProperty(property);
            if (!(userData.getPveProperty().getStateId() <= config.getInitStateId() && userData.getPveProperty().getPowerVal() <= 0L)) {
                // 更新榜单阵营排行榜单
                CrossXiuXianRank rank = new CrossXiuXianRank(String.valueOf(userData.getUserId()), property.getStateId(), userData.getUpdatePropertyTime(), String.valueOf(property.getPowerVal()));
                synchronized (campUserRankMap) {
                    campUserRankMap.putIfAbsent(userData.getCampId(), new CrossXiuXianRankListModel());
                }
                CrossXiuXianRankListModel rankListModel = campUserRankMap.get(userData.getCampId());
                rankListModel.rankChange(rank);
            }
            boolean isLoginSync = temp.getIsLoginSync();
            if (isLoginSync) {
                // 是否登录同步
                loginSyncDataToGame(userData);
            }
        }

    }
    /**
     *
     * 登录同步数据到游戏服
     */
    public void loginSyncDataToGame(CrossXiuXianPvpUserData pvpUserData) {
        XiuXianProto.XiuXianSyncLoginDataRespMsg.Builder respMsg = XiuXianProto.XiuXianSyncLoginDataRespMsg.newBuilder();
        respMsg.setCampId(pvpUserData.getCampId());
        sendPacket(GameProtocol.S_XIU_XIAN_SYNC_LOGIN_FROM_CROSS, respMsg, pvpUserData.getUserId());
    }

    /**
     *
     * 根据服务器id获取宗门id
     */
    public int getCampIdByServerId(long serverId) {
        for (CrossXiuXianPvpCampData campData : pvpCampDataMap.values()) {
            if (campData.getServerIdList().contains(serverId)) {
                return campData.getCampId();
            }
        }
        return 0;
    }
    /**
    * 创建初始化灵峰数据
     * */
    public CrossXiuXianUserMountData initMountData() {
        CrossXiuXianUserMountData mountData = new CrossXiuXianUserMountData();
        XiuXianRoomMemberInfo initRoomInfo = buildDefaultRoomInfo(getCurAllotTime());
        mountData.setNewId(initRoomInfo.getId());
        mountData.setLastId(initRoomInfo.getId());
        Map<Long, XiuXianRoomMemberInfo> roomInfoMap = mountData.getAllAllotMap();
        roomInfoMap.put(initRoomInfo.getId(), initRoomInfo);
        return mountData;
    }

    /**
     * 初始化pvp用户数据
     */
    private CrossXiuXianPvpUserData getPvpUserData(long userId) {
        if (userId == 0) {
            return null;
        }
        if (isNpc(userId)) {
            return npcUserMap.get(userId);
        }
        // 不存在则初始化
        if (!pvpUserDataMap.containsKey(userId)) {
            synchronized (getPlayerLock(userId)) {
                if (!pvpUserDataMap.containsKey(userId)) {
                    long serverId = CrossUserMgr.getServerIdByUserId(userId);
                    // 宗门id
                    int campId = getCampIdByServerId(serverId);
                    if (campId == 0) {
                        return null;
                    }
                    long nowTime = System.currentTimeMillis();
                    CrossXiuXianPvpUserData pvpUserData = new CrossXiuXianPvpUserData();
                    pvpUserData.setActivityId(config.getActivityInfo().getActivityId());
                    pvpUserData.setUserId(userId);
                    // 宗门id
                    pvpUserData.setCampId(campId);
                    // 出生地id
                    pvpUserData.setPlaceId(0);
                    // 可传送时间
                    pvpUserData.setTransferTime(nowTime);
                    // 可复活时间
                    pvpUserData.setReviveTime(nowTime);
                    // 生命标识
                    pvpUserData.setReviveCnt(0);
                    // 灵峰数据
                    pvpUserData.setMountData(initMountData());
                    pvpUserData.setInsertOption();
                    pvpUserDataMap.put(userId, pvpUserData);
                }
            }
        }
        return pvpUserDataMap.get(userId);
    }

    /**
     * 获取当前为第几轮
     */
    public int getCurRound() {
        return DateHelper.calc2DateTDOADays(new Date(config.getActivityInfo().getBeginTime() * 1000), new Date());
    }

    /**
     * 空任务事件,10秒一次
     */
    public void crossXiuXianEmptyTask() {
        logger.info("crossXiuXianEmptyTask");
    }

    /**
     * 挨打同步
     */
    public void crossXiuXianSyncAttackTask() {
        if (!isBattleTime()) {
            return;
        }
        for (int placeId : pvpPlaceDataMap.keySet()) {
            syncPlaceAttack(placeId);
        }
    }

    /**
     * 同步房间被打记录
     */
    private void syncPlaceAttack(int placeId) {
        XiuXianProto.XiuXianAttackedSyncMsg.Builder attackedSyncMsg = XiuXianProto.XiuXianAttackedSyncMsg.newBuilder();
        CrossXiuXianPvpPlaceData placeData = getPvpPlace(placeId);
        if (placeData == null) {
            return;
        }
        synchronized (attackSyncListMap) {
            if (!attackSyncListMap.containsKey(placeId)) {
                return;
            }
            List<CrossXiuXianPvpAttackHelper> attackList = attackSyncListMap.get(placeId);
            if (attackList.size() == 0) {
                return;
            }
            for (CrossXiuXianPvpAttackHelper helper : attackList) {
                attackedSyncMsg.addAttack(parseXiuXianAttackedTemp(helper));
            }
            // 清空记录
            attackSyncListMap.put(placeId, new ArrayList<>());
        }
        // 同步给房间的用户
        sendPacketToAll(ClientProtocol.U_XIU_XIAN_ATTACKED_SYNC, attackedSyncMsg, placeData.getUserList());
    }

    public void crossXiuXianNpcReviveTask() {
        if (!isBattleTime()) {
            return;
        }
        if (!npcRevive) {
            return;
        }
        long nowTime = System.currentTimeMillis();

        if (npcRevive) {
            // 复活机器人进入房间
            for (Long userId : npcUserMap.keySet()) {
                synchronized (getPlayerLock(userId)) {
                    CrossXiuXianPvpUserData userData = npcUserMap.get(userId);
                    if (userData.getPlaceId() == 0 || isBirthPlace(userData.getPlaceId())) {
                        // 没到复活时间
                        if (nowTime < userData.getReviveTime()) {
                            continue;
                        }
                        // 复活
                        revive(userData);
                        // 离开旧房间
                        leavePlace(userData, 4);
                        // 随机加入房间
                        joinPlace(randomHelper.next(5, 19), userData);
                        userData.setTransferTime(nowTime + DateHelper.SECOND_MILLIONS * config.getXIUXIAN_PVP_DELIVERY_CD());
                    } else {
                        if (nowTime > userData.getTransferTime() && nowTime > userData.getAttackTime() + DateHelper.SECOND_MILLIONS * 10) {
                            // 离开旧房间
                            leavePlace(userData, 4);
                            // 随机加入房间
                            joinPlace(randomHelper.next(5, 19), userData);
                            userData.setTransferTime(nowTime + DateHelper.SECOND_MILLIONS * config.getXIUXIAN_PVP_DELIVERY_CD());
                        }
                    }
                }
            }
        }
    }


    /**
     * npc战斗事件
     */
    public void crossXiuXianNpcAttackTask() {
        if (!isBattleTime()) {
            return;
        }
        if (!npcAttack) {
            return;
        }
        // 攻击事件
        for (CrossXiuXianPvpPlaceData placeData : pvpPlaceDataMap.values()) {
            if (placeData == null) {
                continue;
            }
            List<Long> userList = new ArrayList<>(placeData.getUserList());
            for (Long userId : userList) {
                // 这边只处理npc
                if (!isNpc(userId)) {
                    continue;
                }
                long targetUserId = randomGetOtherCampUser(new ArrayList<>(userList), userId);
                if (targetUserId != 0) {
                    attackByCmd(userId, targetUserId);
                }
            }
        }
    }

    private long randomGetOtherCampUser(List<Long> list, long userId) {
        List<Long> randomList = new ArrayList<>();
        int myCampId = getCampByUserId(userId);
        for (Long id : list) {
            if (id == userId) {
                continue;
            }
            if (getCampByUserId(id) == myCampId) {
                continue;
            }
            randomList.add(id);
        }
        if (randomList.size() == 0) {
            return 0;
        }
        return randomList.get(randomHelper.next(0, randomList.size()));
    }

    /**
     * 宝地占点产出
     */
    public void crossXiuXianPlaceSeizeProduce() {
        long nowTime = System.currentTimeMillis();
        if (!isBattleTime()) {
            return;
        }
        Map<Integer, Long> campScoreMap = new ConcurrentHashMap<>();
        for (CrossXiuXianPvpPlaceData placeData : pvpPlaceDataMap.values()) {
            synchronized (getPlaceLock(placeData.getPlaceId())){
                for (CrossXiuXianPvpPlaceSeizeInfo seizeInfo : placeData.getSeizeInfoMap().values()) {
                    if (seizeInfo.getCampId() == placeData.getCampId()) {
                        // 计算产出
                        long seizeProduce = seizeProduce(placeData);
                        campScoreMap.put(seizeInfo.getCampId(), campScoreMap.getOrDefault(seizeInfo.getCampId(), 0L) + seizeProduce);
                        int oldNoticeTime = Math.max(0, (int) ((placeData.getLastNoticeSeizeTime() - placeData.getSeizeTime()) / 1000));
                        // 检测持续占领时间
                        int seizeTime = Math.max(0, (int) ((nowTime - placeData.getSeizeTime()) / 1000));
                        // 判断下击杀是否满足单条命推送公告
                        List<String> noticeParamList = StringUtils.stringToStringList(config.getXIUXIAN_PVP_NOTICE_PLACE_LEVEL_TIME(), "\\|");
                        String params = noticeParamList.get(2);
                        List<Integer> paramList = StringUtils.stringToIntegerList(params, ";");
                        int canNoticeTime = -1;
                        for (int noticeTime : paramList) {
                            if (noticeTime > oldNoticeTime && noticeTime <= seizeTime) {
                                canNoticeTime = noticeTime;
                            }
                        }
                        if (config.getPlaceConfigMap().get(placeData.getPlaceId()).getLevel() >= Integer.parseInt(noticeParamList.get(1)) && canNoticeTime >= 0) {
                            // 添加公告
                            CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
                            noticeData.setActivityId(config.getActivityInfo().getActivityId());
                            noticeData.setRound(getCurRound());
                            noticeData.setCampId(seizeInfo.getCampId());
                            noticeData.setNoticeType(eXiuXianPvpNoticeType.SeizeTime.getValue());
                            noticeData.setContent(placeData.getPlaceId() + "#" + canNoticeTime);
                            noticeData.setNoticeTime(nowTime);
                            noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
                            addPvpNoticeData(noticeData, 0, 0);
                            placeData.setLastNoticeSeizeTime(nowTime);
                        }
                    }
                }
            }

        }
        // 加积分
        for (Map.Entry<Integer, Long> entry : campScoreMap.entrySet()) {
            addCampScore(entry.getKey(), entry.getValue());
        }
    }

    /**
     * 检测房间用户心跳
     */
    public void crossXiuXianCheckPlacePing() {
        long nowTime = System.currentTimeMillis();
        if (!isOpenTime()) {
            return;
        }
        Set<Long> needKickUser = new HashSet<>();
        List<CrossXiuXianPvpPlaceData> list = new ArrayList<>(pvpPlaceDataMap.values());
        for (CrossXiuXianPvpPlaceData placeData : list) {
            for (Long userId : placeData.getUserList()) {
                CrossXiuXianPvpUserData userData = getPvpUserData(userId);
                if (userData == null) {
                    continue;
                }
                // npc 不处理
                if (isNpc(userId)) {
                    continue;
                }
                // 存活的超过10秒没发包踢出去，死亡的1分钟
                if (userData.getUserState() == 0) {
                    if (nowTime - userData.getLastPingPlaceTime() > DateHelper.SECOND_MILLIONS * 10) {
                        needKickUser.add(userId);
                    }
                } else {
                    if (nowTime - userData.getLastPingPlaceTime() > DateHelper.MINUTE_MILLIONS) {
                        needKickUser.add(userId);
                    }
                }

            }
        }
        for (Long userId : needKickUser) {
            CrossXiuXianPvpUserData userData = getPvpUserData(userId);
            if (userData != null) {
                leavePlace(userData, 3);
            }
        }
    }

    /**
     * 抢占宝地定时任务
     */
    public void crossXiuXianSeizePlaceTask() {
        // 活动进行中才处理
        if (!isOpenTime()) {
            return;
        }
        for (int placeId : pvpPlaceDataMap.keySet()) {
            // 定时器不需要同步
            checkPlaceSeizeTime(placeId, false);
        }
    }

    /**
     * 积分同步给活动中的人
     */
    public void crossCampScoreSyncTask() {
        if (!needSyncCampScore) {
            return;
        }
        if (!isOpenTime()) {
            return;
        }
        XiuXianProto.XiuXianCampScoreSyncMsg.Builder builder = XiuXianProto.XiuXianCampScoreSyncMsg.newBuilder();
        List<XiuXianProto.XiuXianCampScoreSyncTemp.Builder> list = getXiuXianCampScoreTempList();
        for (XiuXianProto.XiuXianCampScoreSyncTemp.Builder temp : list) {
            builder.addCampScore(temp);
        }
        sendPacketToAll(Protocol.U_XIU_XIAN_CAMP_SCORE_SYNC, builder, new ArrayList<>(inPvpActivity));
        needSyncCampScore = false;
    }

    /**
     * 获取宗门积分列表
     */
    private List<XiuXianProto.XiuXianCampScoreSyncTemp.Builder> getXiuXianCampScoreTempList() {
        List<XiuXianProto.XiuXianCampScoreSyncTemp.Builder> list = new ArrayList<>();
        List<CrossXiuXianPvpCampData> copy = new ArrayList<>(pvpCampDataMap.values());
        for (CrossXiuXianPvpCampData campData : copy) {
            XiuXianProto.XiuXianCampScoreSyncTemp.Builder temp = XiuXianProto.XiuXianCampScoreSyncTemp.newBuilder();
            temp.setCampId(campData.getCampId());
            temp.setScore(campData.getScore());
            list.add(temp);
        }
        return list;
    }

    /**
     * 活动数据检测 轮次切换需重置数据
     */
    public void crossXiuXianPvpActivityCheckTask() {
        // 检测有没有轮次切换
        synchronized (lock) {
            if (ActivityHelper.activityInTime(config.getActivityInfo()) && crossXiuXianPvpData.getRound() != getCurRound()) {
                // 切换轮次
                crossXiuXianPvpData.setRound(getCurRound());
                // 重置活动数据
                resetPvpActivityData();
                // 重置房间数据
                resetPlaceData();
                // 重置宗门相关数据
                resetCampData();
                // 重置用户数据
                resetUserData();
                // 清除公告
                noticeDataList.clear();
                for (LinkedList<CrossXiuXianPvpNoticeData> list : campNoticeDataMap.values()) {
                    list.clear();
                }
            }
            long nowTime = System.currentTimeMillis();
            // 检测活动状态
            // 是否需要同步结算
            boolean needEndSync = false;
            if (nowTime < config.getActivityInfo().getBeginTime() * 1000) {
                crossXiuXianPvpData.setActivityState(eXiuXianPvpActivityStateType.NotStart.getValue());
            } else if (nowTime > config.getActivityInfo().getEndTime() * 1000) {
                if (crossXiuXianPvpData.getActivityState() != eXiuXianPvpActivityStateType.End.getValue()) {
                    needEndSync = true;
                }
                crossXiuXianPvpData.setActivityState(eXiuXianPvpActivityStateType.End.getValue());
            } else if (nowTime >= config.getPvpPrepareTime() && nowTime < config.getPvpStartTime()) {
                // 准备中
                crossXiuXianPvpData.setActivityState(eXiuXianPvpActivityStateType.Prepare.getValue());
            } else if (nowTime >= config.getPvpStartTime() && nowTime < config.getPvpEndTime()) {
                // 进行中
                crossXiuXianPvpData.setActivityState(eXiuXianPvpActivityStateType.Battle.getValue());
            } else if (nowTime >= config.getPvpEndTime()) {
                // 已结束
                if (crossXiuXianPvpData.getActivityState() != eXiuXianPvpActivityStateType.End.getValue()) {
                    needEndSync = true;
                }
                crossXiuXianPvpData.setActivityState(eXiuXianPvpActivityStateType.End.getValue());
            }
            // 检测下结束公告
            List<String> noticeParamList = StringUtils.stringToStringList(config.getXIUXIAN_PVP_NOTICE_BATTLE_END_TIME(), "\\|");
            String params = noticeParamList.get(1);
            List<Integer> paramList = StringUtils.stringToIntegerList(params, ";");
            // updateTime 差值判断
            long oldTimeOffset = (config.getPvpEndTime() - crossXiuXianPvpData.getUpdateTime()) / 1000;
            long newTimeOffset = (config.getPvpEndTime() - nowTime) / 1000;
            long noticeTime = -1;
            for (int time : paramList) {
                if (oldTimeOffset > time && time >= newTimeOffset) {
                    noticeTime = time;
                }
            }
            if (noticeTime > 0) {
                // 添加公告
                CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
                noticeData.setActivityId(config.getActivityInfo().getActivityId());
                noticeData.setRound(getCurRound());
                noticeData.setCampId(0);
                noticeData.setNoticeType(eXiuXianPvpNoticeType.PvpTimeEnd.getValue());
                noticeData.setContent(String.valueOf(noticeTime / 60));
                noticeData.setNoticeTime(nowTime);
                noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
                addPvpNoticeData(noticeData, 0, 0);
            }
            // 积分到达指定的值提前结束
            if (getCampMaxScore() >= config.getPvpBattleTimeEndCondition().get(1)) {
                // 已结束
                if (crossXiuXianPvpData.getActivityState() != eXiuXianPvpActivityStateType.End.getValue()) {
                    needEndSync = true;
                }
                crossXiuXianPvpData.setActivityState(eXiuXianPvpActivityStateType.End.getValue());
            }
            crossXiuXianPvpData.setUpdateTime(nowTime);
            if (needEndSync) {
                // 结束了同步结算数据
                xiuXianPvpEndSync();
            }
        }
    }

    /**
     * 锁定名单
     */
    public void crossXiuXianLockDataTask() {
        if (crossXiuXianPvpData.isLockState()) {
            return;
        }
        synchronized (lock) {
            if (crossXiuXianPvpData.isLockState()) {
                return;
            }
            long now = System.currentTimeMillis();

            // 没到锁定时间
            if (now < config.getPvpPrepareTime()) {
                return;
            }
            // 开始锁定
            // 锁定每个阵营的前100名
            int limit = config.getXIUXIAN_PVP_JOIN_CONDITION();
            for (CrossXiuXianRankListModel rankListModel : campUserRankMap.values()) {
                int rankNum = 0;
                LinkedList<CrossXiuXianRank> rankList = rankListModel.getRankList();
                for (CrossXiuXianRank rank : rankList) {
                    rankNum++;
                    if (rankNum > limit) {
                        break;
                    }
                    long userId = Long.parseLong(rank.getId());
                    CrossXiuXianPvpUserData userData = getPvpUserData(userId);
                    if (userData == null) {
                        continue;
                    }
                    // 锁定时更新下属性
                    updatePvpProperty(userData);
                    // 锁定名单
                    userData.setPvpAble(true);
                }
            }
            // 锁定每个阵营的宗主
            for (CrossXiuXianPvpCampData campData : pvpCampDataMap.values()) {
                // 获取仙力最高的人
                long userId = getCampMaxAbilityUserId(campData.getCampId());
                campData.setMajorUserId(userId);
            }
            // 锁定状态
            crossXiuXianPvpData.setLockState(true);
        }
    }
    /**
     * 灵峰分配
     */
    public void crossXiuXianMountAllotTask() {
        long nowTime = System.currentTimeMillis();

        // 当活动还没开始时候不分配
        if (!ActivityHelper.activityInTime(config.getActivityInfo())) {
            return;
        }

        // 大于等于活动结束时间不分配(最后一轮活动结束了，不进行分配)
        long nextAllotTime = getNextAllotTime(nowTime);
        if (nextAllotTime >= config.getActivityInfo().getEndTime()) {
            return;
        }

        Map<Integer, Map<Integer, Map<Integer, List<Long>>>> tempMountRoomMap = new ConcurrentHashMap<>();
        Map<Long, XiuXianRoomMemberInfo> tempRoomMap = new ConcurrentHashMap<>();

        // 获取生成序号(已分配时间为id)
        long allotId = getCurAllotTime(nowTime);

        // 活动开始第一次不分配
        if (allotId == config.getActivityInfo().getBeginTime()) {
            return;
        }

        // 超过一分钟不分配
        if (nowTime / 1000 > (allotId + 60)) {
            return;
        }

        // 如果已经生成过就不再执行分配逻辑
        if (allotMap.containsKey(allotId)) {
            return;
        }

        // 获取灵峰id列表并排序
        List<Integer> peakIdList = new ArrayList<>(config.getPeakConfigMap().keySet());
        Collections.sort(peakIdList);
        // 容纳人数== 灵峰id ： [总容纳人数、房间容纳人数]  treeMap key升序
        Map<Integer, List<Integer>> capacityTreeMap = new TreeMap<>();
        int endNum = 0;
        for (Integer peakId : peakIdList) {
            if (peakId == config.getDefaultMount()) {
                continue;
            }
            XiuXianPeakConfig peakConfig = config.getPeakConfigMap().get(peakId);
            int tempNum = peakConfig.getRoomNum() * peakConfig.getPeopleNum();
            endNum += tempNum;
            List<Integer> tempList = new ArrayList<>();
            tempList.add(tempNum);
            tempList.add(peakConfig.getPeopleNum());
            capacityTreeMap.put(peakId, tempList);
        }

        for (Map.Entry<Integer, CrossXiuXianRankListModel> entry : campUserRankMap.entrySet()) {
            int rankNum = 0;
            LinkedList<CrossXiuXianRank> rankList = new LinkedList<>(entry.getValue().getRankList());
            for (CrossXiuXianRank rank : rankList) {
                rankNum++;
                if (rankNum > endNum) {
                    break;
                }
                int mountId = 0;        // 灵峰id
                int roomId = 0;         // 房间id
                int posId = 0;          // 位置id
                int tempRank = rankNum; // 当前排名玩家的名次
                for (Map.Entry<Integer, List<Integer>> peakEntry : capacityTreeMap.entrySet()) {

                    // 排名大于等于灵峰总容纳数量  就减去灵峰的容纳数量
                    if (tempRank > peakEntry.getValue().get(0)) {
                        tempRank -= peakEntry.getValue().get(0);
                        continue;
                    }

                    // 取灵峰id
                    mountId = peakEntry.getKey();

                    // tempRank超出当前最早灵峰位置的排名数量
                    if (tempRank % peakEntry.getValue().get(1) == 0) {
                        roomId = tempRank/peakEntry.getValue().get(1);
                        posId = peakEntry.getValue().get(1);
                    } else {
                        roomId = tempRank/peakEntry.getValue().get(1) + 1;
                        posId = tempRank % peakEntry.getValue().get(1);
                    }
                    break;
                }
                XiuXianRoomMemberInfo roomMemberInfo = new XiuXianRoomMemberInfo(allotId, mountId, roomId, posId, rankNum);
                tempRoomMap.put(Long.valueOf(rank.getId()), roomMemberInfo);
                // 初始化房间数据
                insertCampMountRoom(tempMountRoomMap, entry.getKey(), mountId, roomId, Long.valueOf(rank.getId()));
            }
        }
        // 更新用户数据
        for (CrossXiuXianPvpUserData userData : pvpUserDataMap.values()) {
            CrossXiuXianUserMountData mountData = userData.getMountData();
            // 更新最新分配id
            mountData.setNewId(allotId);
            XiuXianRoomMemberInfo roomMemberInfo = tempRoomMap.get(userData.getUserId());
            if (roomMemberInfo == null) {
                roomMemberInfo = buildDefaultRoomInfo(allotId);
            }
            // 更新玩家内存
            Map<Long, XiuXianRoomMemberInfo> userRoomInfoMap = mountData.getAllAllotMap();
            userRoomInfoMap.put(allotId, roomMemberInfo);
            userData.setMountData(mountData);
        }
        allotMap.put(allotId, tempRoomMap);
        // 覆盖原有的值
        campMountRoomMap = tempMountRoomMap;

        // 同步信息给房间内玩家
        syncMountChangeInfo();

        // 新增分配信息
        CrossXiuXianMountAllotData mountAllotData = mountAllotDataMap.get(allotId);
        if (mountAllotData == null) {
            mountAllotData = new CrossXiuXianMountAllotData();
            mountAllotData.setActivityId(config.getActivityInfo().getActivityId());
            mountAllotData.setAllotTimeId(allotId);
            mountAllotData.setAckServerIdList(new ArrayList<>());
            mountAllotData.setInsertOption();
            mountAllotDataMap.put(allotId, mountAllotData);
        }
        // 同步灵峰分配
        crossXiuXianSyncMountAllotTask();
    }
    /**
     * 同步灵峰分配
     */
    public void crossXiuXianSyncMountAllotTask() {
        // 是否是活动结束期（+100s）不进行定时任务
        long nowTime = System.currentTimeMillis() / 1000;
        if (nowTime > (config.getActivityInfo().getEndTime() + 100)) {
            return;
        }
        // 检测是否同步完成 (兼容同步旧的分配)
        for ( Map.Entry<Long, CrossXiuXianMountAllotData> entryAllotData : mountAllotDataMap.entrySet()) {
            long temAllotId = entryAllotData.getKey();
            CrossXiuXianMountAllotData mountAllotData = entryAllotData.getValue();
            List<Long> serverIdList = config.getActivityInfo().getServerIdList();
            List<Long> needServerList = new ArrayList<>();
            for (Long serverId : serverIdList) {
                if (mountAllotData.getAckServerIdList().contains(serverId)) {
                    continue;
                }
                needServerList.add(serverId);
            }
            if (needServerList.size() == 0) {
                // 同步完毕
                continue;
            }
            // 封装同步
            Map<Long, XiuXianRoomMemberInfo> curAllotMap = allotMap.get(temAllotId);
            if (curAllotMap == null) {
                return;
            }
            Map<Long, List<XiuXianProto.XiuXianUserMountAllotInfoTemp>> serverUserMap = new ConcurrentHashMap<>();
            for (Map.Entry<Long, XiuXianRoomMemberInfo> entry : curAllotMap.entrySet()) {
                long userId = entry.getKey();
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
                if (null == userBaseInfo) {continue;}
                if (!needServerList.contains(userBaseInfo.getServerId())) {
                    continue;
                }
                if (!serverUserMap.containsKey(userBaseInfo.getServerId())) {
                    serverUserMap.put(userBaseInfo.getServerId(), new ArrayList<>());
                }
                XiuXianProto.XiuXianUserMountAllotInfoTemp.Builder infoTemp = XiuXianProto.XiuXianUserMountAllotInfoTemp.newBuilder();
                infoTemp.setUserId(userId);
                infoTemp.setMountId(entry.getValue().getMountId());
                infoTemp.setActivityId(config.getActivityInfo().getActivityId());
                serverUserMap.get(userBaseInfo.getServerId()).add(infoTemp.build());
            }
            for (Long serverId : needServerList) {
                XiuXianProto.CrossXiuXianSyncAllotMountMsg.Builder respMsg = XiuXianProto.CrossXiuXianSyncAllotMountMsg.newBuilder();
                respMsg.setCurAllotTime(temAllotId);
                respMsg.setActivityId(config.getActivityInfo().getActivityId());
                List<XiuXianProto.XiuXianUserMountAllotInfoTemp> allotInfoList = serverUserMap.get(serverId);
                if (allotInfoList != null) {
                    respMsg.addAllUserAllotList(allotInfoList);
                }
                YanQuMessage message = YanQuMessageUtils.buildMessage(GameProtocol.S_XIU_XIAN_SYNC_ALLOT_MOUNT_FROM_CROSS, respMsg);
                MessageHelper.sendPacket(serverId, 0, message);
            }
        }
    }

    private List<Long> getNeedGetScoreServerList() {
        List<Long> list = new ArrayList<>();
        List<Long> serverIdList = config.getActivityInfo().getServerIdList();
        // 已采集完的区服
        List<Long> noNeedServerIdList = new ArrayList<>();
        for (CrossXiuXianServerScoreData data : serverScoreDataList) {
            noNeedServerIdList.addAll(data.getServerIdList());
        }
        for (Long serverId : serverIdList) {
            if (noNeedServerIdList.contains(serverId)) {
                continue;
            }
            list.add(serverId);
        }
        return list;
    }


    /**
     * 区服数据采集
     */
    public void crossXiuXianGetServerScoreTask() {
        synchronized (lock) {
            // 判断下是否有需要待采集的区服
            List<Long> serverList = getNeedGetScoreServerList();
            if (serverList.size() == 0) {
                // 采集完毕
                return;
            }
            // 获取近七天数据
            long beginTime = (DateHelper.getTodayZeroTimeStamp() - 7 * DateHelper.DAY_MILLIONS);
            XiuXianProto.XiuXianGetServerScoreToGameServerMsg.Builder builder = XiuXianProto.XiuXianGetServerScoreToGameServerMsg.newBuilder();
            builder.setActivityId(config.getActivityInfo().getActivityId());
            builder.setBeginTime(beginTime);
            // 到区服取数据
            for (Long serverId : serverList) {
                MessageHelper.sendPacket(serverId, -1, YanQuMessageUtils.buildMessage(GameProtocol.S_XIU_XIAN_GET_SERVER_SCORE_FROM_CROSS, builder));
            }
        }
    }

    public void crossXiuXianGenCampTask() {
        if (crossXiuXianPvpData.isGenCampState()) {
            // 已锁定完成不再处理
            return;
        }
        synchronized (lock) {
            if (crossXiuXianPvpData.isGenCampState()) {
                // 已锁定完成不再处理
                return;
            }
            // 判断下是否有需要待采集的区服
            List<Long> serverList = getNeedGetScoreServerList();
            if (serverList.size() > 0) {
                // 未采集完毕
                // 判断下是否超过最长等待时间
                List<Integer> paramList = StringUtils.stringToIntegerList(config.getXIUXIAN_SECT_SCORE_DEFAULT(), "\\|");
                if (System.currentTimeMillis() / 1000 - config.getActivityInfo().getBeginShowTime() > paramList.get(1)) {
                    // 添加保底评分
                    for (Long serverId : serverList) {
                        getServerScore(serverId, paramList.get(0));
                    }
                } else {
                    return;
                }
            }
            // 分配分组
            genCamp();
//            Map<Integer, XiuXianGenCampHelper> campHelperMap = new ConcurrentHashMap<>();
//            // 按评分，将所有数组从到大进行排序
//            serverScoreDataList.sort(Comparator.comparingLong(CrossXiuXianServerScoreData::getServerScore));
//            // 将评分最小的四组数，分别塞入四个宗门(随机)
//            List<CrossXiuXianServerScoreData> list = new ArrayList<>(serverScoreDataList);
//            // 记录下已分配的分组
//            Set<String> groupUuidSet = new HashSet<>();
//            // 记录下已分配的区服(防止重复分配)
//            Set<Long> assignedServerIdList = new HashSet<>();
//            Set<Integer> campIdSet = pvpCampDataMap.keySet();
//            for (int campId : campIdSet) {
//                if (list.size() == 0) {
//                    break;
//                }
//                CrossXiuXianServerScoreData scoreData = list.remove(0);
//                if (scoreData == null || groupUuidSet.contains(scoreData.getUuid())) {
//                    continue;
//                }
//                groupUuidSet.add(scoreData.getUuid());
//                XiuXianGenCampHelper helper = new XiuXianGenCampHelper();
//                helper.setCampId(campId);
//                Set<Long> tempServerIdList = new HashSet<>();
//                for (long serverId : scoreData.getServerIdList()) {
//                    if (assignedServerIdList.contains(serverId)) {
//                        continue;
//                    }
//                    assignedServerIdList.add(serverId);
//                    tempServerIdList.add(serverId);
//                }
//                helper.setServerIdList(tempServerIdList);
//                helper.setServerScore(scoreData.getServerScore());
//                campHelperMap.put(campId, helper);
//            }
//            // 第二次开始，塞入数组池中评分最大的数组
//            while (list.size() > 0) {
//                CrossXiuXianServerScoreData scoreData = list.remove(list.size() - 1);
//                int insertCamp = 0;
//                if (scoreData != null && !groupUuidSet.contains(scoreData.getUuid())) {
//                    // 获取一下待塞范围
//                    List<Integer> allInsertCamp = getAllInsertCamp(campHelperMap);
//                    if (allInsertCamp.size() > 1) {
//                        // 获取区服最少的宗门
//                        List<Integer> minServerCountCampList = getMinServerCountCamp(campHelperMap, allInsertCamp);
//                        if (minServerCountCampList.size() > 1) {
//                            // 若有多个区服最少的数组，则从中选评分最小的数组塞入数组
//                            List<Integer> minScoreCampList = getMinScoreCampList(campHelperMap, minServerCountCampList);
//                            // 若区服最少的数组中，评分又有相同的，则随机选一个宗门塞入
//                            insertCamp = minScoreCampList.get(randomHelper.next(0, minScoreCampList.size()));
//                        } else if (minServerCountCampList.size() == 1) {
//                            insertCamp = minServerCountCampList.get(0);
//                        }
//                    } else if (allInsertCamp.size() == 1) {
//                        insertCamp = allInsertCamp.get(0);
//                    }
//                }
//                if (insertCamp != 0) {
//                    groupUuidSet.add(scoreData.getUuid());
//                    // 塞进分组的宗门
//                    XiuXianGenCampHelper helper = campHelperMap.get(insertCamp);
//                    Set<Long> tempServerIdList = new HashSet<>();
//                    for (long serverId : scoreData.getServerIdList()) {
//                        if (assignedServerIdList.contains(serverId)) {
//                            continue;
//                        }
//                        assignedServerIdList.add(serverId);
//                        tempServerIdList.add(serverId);
//                    }
//                    helper.setServerScore(helper.getServerScore() + scoreData.getServerScore());
//                    Set<Long> serverIdList = new HashSet<>(helper.getServerIdList());
//                    serverIdList.addAll(tempServerIdList);
//                    helper.setServerIdList(serverIdList);
//                    campHelperMap.put(insertCamp, helper);
//                }
//            }
//            // 完成后分配下区服
//            for (Map.Entry<Integer, XiuXianGenCampHelper> entry : campHelperMap.entrySet()) {
//                int campId = entry.getKey();
//                Set<Long> serverIdList = entry.getValue().getServerIdList();
//                // 区服加一下
//                CrossXiuXianPvpCampData campData = getPvpCampData(campId);
//                if (campData == null) {
//                    continue;
//                }
//                campData.setServerIdList(new HashSet<>(serverIdList));
//                logger.info("分配成功，宗门:{},区服数量:{},总评分:{}", entry.getValue().getCampId(), entry.getValue().getServerIdList().size(), entry.getValue().getServerScore());
//            }
            // 设置下锁定状态
            crossXiuXianPvpData.setGenCampState(true);
        }
    }

    /**
     * 6.0 新的分配规则
     */
    public void genCamp() {
        Map<Integer, List<CrossXiuXianServerScoreData>> resultMap = new HashMap<>();
        List<Integer> campIdList = new ArrayList<>(pvpCampDataMap.keySet());
        // 这里也打乱下吧
        Collections.shuffle(campIdList);
        // 最小方差
        double min = Double.MAX_VALUE;
        for (int i = 0; i < 1000; i++) {
            Map<Integer, List<CrossXiuXianServerScoreData>> map = new HashMap<>();
            // 打乱一下
            Collections.shuffle(serverScoreDataList);
            for (int j = 0; j < serverScoreDataList.size(); j++) {
                int campId = campIdList.get(j % campIdList.size());
                List<CrossXiuXianServerScoreData> list = map.getOrDefault(campId, new ArrayList<>());
                list.add(serverScoreDataList.get(j));
                map.put(campId, list);
            }
            // 算下宗门总分
            Map<Integer, Long> campScoreMap = new HashMap<>();
            for (Map.Entry<Integer, List<CrossXiuXianServerScoreData>> entry : map.entrySet()) {
                for (CrossXiuXianServerScoreData scoreData : entry.getValue()) {
                    campScoreMap.put(entry.getKey(), campScoreMap.getOrDefault(entry.getKey(), 0L) + scoreData.getServerScore());
                }
            }
            // 计算下宗门的方差
            double variance = calculateVariance(new ArrayList<>(campScoreMap.values()));
            if (variance < min) {
                min = variance;
                resultMap = map;
            }
        }
        // 完成后分配下区服
        for (Map.Entry<Integer, List<CrossXiuXianServerScoreData>> entry : resultMap.entrySet()) {
            int campId = entry.getKey();
            long totalScore = 0;
            CrossXiuXianPvpCampData campData = getPvpCampData(campId);
            if (campData == null) {
                continue;
            }
            campData.getServerIdList().clear();
            // 区服加一下
            for (CrossXiuXianServerScoreData scoreData : entry.getValue()) {
                logger.info("【凡人修仙传宗门分配】活动id:{},宗门:{},区服:{},评分:{}", config.getActivityInfo().getActivityId(), campId, scoreData.getServerIdList(), scoreData.getServerScore());
                campData.getServerIdList().addAll(new HashSet<>(scoreData.getServerIdList()));
                totalScore += scoreData.getServerScore();
            }
            campData.setUpdateOption();
            logger.info("【凡人修仙传宗门分配】活动id:{},分配成功,宗门:{},总区服数量:{},总评分:{},方差:{}", config.getActivityInfo().getActivityId(), campId, campData.getServerIdList().size(), totalScore, min);
        }
    }

    /**
     * 计算方差
     * @param scoreList 分数
     */
    private double calculateVariance(List<Long> scoreList) {
        double mean = 0.0;
        for (double num : scoreList) {
            mean += num;
        }
        mean = mean / scoreList.size();

        double temp = 0;
        for (double num : scoreList) {
            temp += (num - mean) * (num - mean);
        }
        return temp / (scoreList.size());
    }

    private List<Integer> getMinScoreCampList(Map<Integer, XiuXianGenCampHelper> campHelperMap, List<Integer> minServerCountCampList) {
        List<Integer> list = new ArrayList<>();
        long minServerScore = Long.MAX_VALUE;
        for (XiuXianGenCampHelper helper : campHelperMap.values()) {
            if (!minServerCountCampList.contains(helper.getCampId())) {
                continue;
            }
            minServerScore = Math.min(helper.getServerScore(), minServerScore);
        }
        for (XiuXianGenCampHelper helper : campHelperMap.values()) {
            if (!minServerCountCampList.contains(helper.getCampId())) {
                continue;
            }
            if (helper.getServerScore() == minServerScore) {
                list.add(helper.getCampId());
            }
        }
        return list;
    }

    private List<Integer> getMinServerCountCamp(Map<Integer, XiuXianGenCampHelper> campHelperMap, List<Integer> allInsertCamp) {
        List<Integer> list = new ArrayList<>();
        int minCount = Integer.MAX_VALUE;
        for (XiuXianGenCampHelper helper : campHelperMap.values()) {
            if (!allInsertCamp.contains(helper.getCampId())) {
                continue;
            }
            minCount = Math.min(minCount, helper.getServerIdList().size());
        }
        for (XiuXianGenCampHelper helper : campHelperMap.values()) {
            if (!allInsertCamp.contains(helper.getCampId())) {
                continue;
            }
            if (helper.getServerIdList().size() == minCount) {
                list.add(helper.getCampId());
            }
        }
        return list;
    }

    private List<Integer> getAllInsertCamp(Map<Integer, XiuXianGenCampHelper> campHelperMap) {
        List<Integer> list = new ArrayList<>();
        long minServerScore = Long.MAX_VALUE;
        for (XiuXianGenCampHelper helper : campHelperMap.values()) {
            minServerScore = Math.min(helper.getServerScore(), minServerScore);
        }
        for (XiuXianGenCampHelper helper : campHelperMap.values()) {
            if (helper.getServerScore() - minServerScore <= config.getXIUXIAN_SECT_JUDGE_PRM()) {
                list.add(helper.getCampId());
            }
        }
        return list;
    }


    /**
     * 重置活动数据
     */
    public void resetPvpActivityData() {
        // 重置活动数据
        crossXiuXianPvpData.setLockState(false);
        crossXiuXianPvpData.setActivityState(eXiuXianPvpActivityStateType.NotStart.getValue());
    }

    /**
     * 重置房间数据
     */
    public void resetPlaceData() {
        for (CrossXiuXianPvpPlaceData pvpPlaceData : pvpPlaceDataMap.values()) {
            XiuXianPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(pvpPlaceData.getPlaceId());
            Set<Long> userList = pvpPlaceData.getUserList();
            userList.clear();
            pvpPlaceData.setUserList(userList);
            // 出生点不处理
            if (placeConfig.getType() != eXiuXianPvpPlaceType.Place.getValue()) {
                continue;
            }
            for (Map.Entry<Integer, CrossXiuXianPvpPlaceSeizeInfo> entry : pvpPlaceData.getSeizeInfoMap().entrySet()) {
                entry.getValue().setCampId(entry.getKey());
                entry.getValue().setSeizeTime(0);
            }
            pvpPlaceData.setLastSeizeCampId(0);
            pvpPlaceData.setCampId(0);
            pvpPlaceData.setUpdateTime(System.currentTimeMillis());
            pvpPlaceData.setUpdateOption();
        }
    }

    /**
     * 重置宗门数据
     */
    public void resetCampData(){
        for (CrossXiuXianPvpCampData campData : pvpCampDataMap.values()) {
            campData.setScore(0);
            campData.setMajorUserId(0);
            campData.setMajorPlaceId(0);
            campData.setMinorUserId(0);
            campData.setMinorPlaceId(0);
            campData.setMajorMarkTime(0);
            campData.setMinorMarkTime(0);
            campData.setUpdateScoreTime(System.currentTimeMillis());
            // 更新下本轮宗门积分榜单
            campScoreRankMap.rankChange(new CrossXiuXianRank(String.valueOf(campData.getCampId()), campData.getScore(), campData.getUpdateScoreTime()));
        }
    }

    /**
     * 重置用户数据
     */
    public void resetUserData(){
        for (CrossXiuXianPvpUserData userData : pvpUserDataMap.values()) {
            // 重置房间位置
            userData.setPlaceId(0);
            userData.setBattleRecord(new CrossXiuXianPvpBattleRecord());
            userData.setReviveCnt(0);
            // 资格重置下
            userData.setPvpAble(false);
        }
    }


    /**
     * 同步房间内的用户数据
     */
    public void syncPlaceUserData() {
        if (!isOpenTime()) {
            return;
        }
        List<CrossXiuXianPvpPlaceData> list = new ArrayList<>(pvpPlaceDataMap.values());
        for (CrossXiuXianPvpPlaceData placeData : list) {
            if (placeData.getPlaceId() == 0) {
                continue;
            }
            Set<Long> userList = placeData.getUserList();
            if (userList.size() == 0) {
                // 没有用户就不需要同步了
                continue;
            }
            // 同步用户给房间内的用户
            XiuXianProto.XiuXianPlaceSyncMsg.Builder builder = XiuXianProto.XiuXianPlaceSyncMsg.newBuilder();
            for (Long userId : userList) {
                CrossXiuXianPvpUserData pvpUserData = getPvpUserData(userId);
                if (pvpUserData == null) {
                    continue;
                }
                if (!isBirthPlace(placeData.getPlaceId()) && pvpUserData.getUserState() == 1) {
                    continue;
                }
                XiuXianProto.XiuXianPvpSimpleUserTemp.Builder userTemp = XiuXianProto.XiuXianPvpSimpleUserTemp.newBuilder();
                userTemp.setUserId(userId);
                userTemp.setPosition(parseXiuXianPvpPositionTemp(pvpUserData.getPosition()));
                builder.addUser(userTemp);
            }
            sendPacketToAll(ClientProtocol.U_XIU_XIAN_PLACE_SYNC, builder, userList);
        }
    }

    public CrossXiuXianPvpCampData getPvpCampData(int campId) {
        return pvpCampDataMap.get(campId);
    }

    /**
     * 是否有资格
     */
    public boolean isAble(long userId) {
        if (isNpc(userId)) {
            return true;
        }
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        return userData != null && userData.isPvpAble();
    }

    /**
     * 玩家进入pvp请求数据
     *
     * @param userId 玩家id
     */
    public int enterPvpByCmd(long userId) {
        // 判断下资格
        if (!crossXiuXianPvpData.isLockState()) {
            return GameErrorCode.E_XIU_XIAN_PVP_IN_LOCK_STATE;
        }
        XiuXianProto.XiuXianEnterPvpRespMsg.Builder builder = XiuXianProto.XiuXianEnterPvpRespMsg.newBuilder();
        builder.setRet(0);
        boolean able = isAble(userId);
        builder.setAble(able);
        if (!able) {
            // 没资格就返回
            sendPacket(ClientProtocol.U_XIU_XIAN_ENTER_PVP, builder, userId);
            return 0;
        }
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            // 没数据也返回
            sendPacket(ClientProtocol.U_XIU_XIAN_ENTER_PVP, builder, userId);
            return 0;
        }
        inPvpActivity.add(userId);
        CrossXiuXianPvpCampData campData = getPvpCampData(userData.getCampId());
        // 做个容错，正常不会出现,没有宗主设置下宗主
        if (campData.getMajorUserId() == 0) {
            campData.setMajorUserId(userId);
        }
        // 如果是死亡状态，处理下复活
        if (userData.getUserState() == 1) {
            revive(userData);
        }
        // 进入pvp默认给丢到出生点
        // 离开原来的房间
        leavePlace(userData, 1);
        // 进入出生点
        joinPlace(userData.getCampId(), userData);
        // 用户数据
        builder.setPvpUserData(parseXiuXianPvpUserDataTemp(userData));
        // 阵营信息
        builder.setCamp(parseXiuXianCampTemp(campData));
        // 房间信息
        XiuXianProto.XiuXianPvpPlaceInfoTemp.Builder placeInfoTemp = parseXiuXianPvpPlaceInfoTemp(getPvpPlace(userData.getPlaceId()));
        if (placeInfoTemp != null) {
            builder.setPlace(placeInfoTemp);
        }

        // 公告信息
        XiuXianProto.XiuXianNoticeListMsg.Builder noticeList = XiuXianProto.XiuXianNoticeListMsg.newBuilder();
        // 全服公告
        for (CrossXiuXianPvpNoticeData noticeData : noticeDataList) {
            XiuXianProto.XiuXianNoticeTemp.Builder noticeTemp = parseXiuXianNoticeTemp(noticeData);
            if (noticeTemp != null) {
                noticeList.addNotice(noticeTemp);
            }
        }
        // 宗门公告
        for (CrossXiuXianPvpNoticeData noticeData : campNoticeDataMap.get(userData.getCampId())) {
            XiuXianProto.XiuXianNoticeTemp.Builder noticeTemp = parseXiuXianNoticeTemp(noticeData);
            if (noticeTemp != null) {
                noticeList.addCampNotice(noticeTemp);
            }
        }
        builder.setNoticeList(noticeList);

        sendPacket(ClientProtocol.U_XIU_XIAN_ENTER_PVP, builder, userId);

        // 同步下积分
        XiuXianProto.XiuXianCampScoreSyncMsg.Builder campScoreBuilder = XiuXianProto.XiuXianCampScoreSyncMsg.newBuilder();
        List<XiuXianProto.XiuXianCampScoreSyncTemp.Builder> list = getXiuXianCampScoreTempList();
        for (XiuXianProto.XiuXianCampScoreSyncTemp.Builder temp : list) {
            campScoreBuilder.addCampScore(temp);
        }
        sendPacket(Protocol.U_XIU_XIAN_CAMP_SCORE_SYNC, campScoreBuilder, userId);

        return 0;
    }

    private XiuXianProto.XiuXianNoticeTemp.Builder parseXiuXianNoticeTemp(CrossXiuXianPvpNoticeData noticeData) {
        if (noticeData == null) {
            return null;
        }
        XiuXianProto.XiuXianNoticeTemp.Builder builder = XiuXianProto.XiuXianNoticeTemp.newBuilder();
        CrossXiuXianPvpNoticeUserData user1 = noticeData.getUser1();
        if (user1.getUserId() != 0) {
            XiuXianProto.XiuXianNoticeUserTemp.Builder user1Temp = XiuXianProto.XiuXianNoticeUserTemp.newBuilder();
            user1Temp.setServerId(user1.getServerId());
            user1Temp.setNickName(user1.getNickName());
            user1Temp.setDecoration(user1.getDecoration());
            user1Temp.setStateId(user1.getStateId());
            builder.setUser1(user1Temp);
        }
        CrossXiuXianPvpNoticeUserData user2 = noticeData.getUser2();
        if (user2.getUserId() != 0) {
            XiuXianProto.XiuXianNoticeUserTemp.Builder user2Temp = XiuXianProto.XiuXianNoticeUserTemp.newBuilder();
            user2Temp.setServerId(user2.getServerId());
            user2Temp.setNickName(user2.getNickName());
            user2Temp.setDecoration(user2.getDecoration());
            user2Temp.setStateId(user2.getStateId());
            builder.setUser2(user2Temp);
        }
//        if (userId != 0) {
//            if (isNpc(userId)) {
//                CrossXiuXianNpcDataHelper dataHelper = npcDataMap.get(userId);
//                builder.setNickName(dataHelper.getNickName());
//                builder.setServerId(dataHelper.getServerId());
//            } else {
//                CrossUserBaseInfo userBaseInfo = CrossUserMgr.getCrossUserBaseInfo(userId);
//                if (userBaseInfo != null) {
//                    builder.setNickName(userBaseInfo.getUserBaseInfo().getNickName());
//                    builder.setServerId(userBaseInfo.getUserBaseInfo().getServerId());
//                }
//            }
//        }
        builder.setCampId(noticeData.getCampId());
        builder.setNoticeType(noticeData.getNoticeType());
        builder.setContent(noticeData.getContent());
        builder.setNoticeTime(noticeData.getNoticeTime());
        builder.setIsRoll(noticeData.getIsRoll());
        return builder;
    }

    /**
     * 离开pvp
     */
    public int leavePvpByCmd(long userId) {
        inPvpActivity.remove(userId);
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData != null) {
            // 如果在房间状态，则退出房间
            leavePlace(userData, 1);
            XiuXianProto.XiuXianLeavePvpRespMsg.Builder builder = XiuXianProto.XiuXianLeavePvpRespMsg.newBuilder();
            builder.setRet(0);
            sendPacket(ClientProtocol.U_XIU_XIAN_LEAVE_PVP, builder, userId);
        }
        return 0;
    }

    /**
     * 离线处理
     */
    public void offLineByCmd(long userId) {
        // 历练界面离线去除
        leavePracticeByCmd(userId);
        // 离开pvp
        leavePvpByCmd(userId);
        // 离线离开灵峰房间
        checkRoomOutPlayers(userId);
    }

    /**
     * 进入(传送)房间
     *
     * @param userId 玩家id
     */
    public int enterPlaceByCmd(long userId, int placeId) {
        CrossXiuXianPvpPlaceData placeData = getPvpPlace(placeId);
        if (placeData == null) {
            return GameErrorCode.E_XIU_XIAN_PLACE_NOT_FOUND;
        }
        if (!isAble(userId)) {
            return GameErrorCode.E_XIU_XIAN_PVP_NO_ABLE;
        }
        CrossXiuXianPvpUserData pvpUserData = getPvpUserData(userId);
        if (pvpUserData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        // 判断下房间的人数是否上限
        if (placeId != 0 && checkCampPlayerLimit(pvpUserData.getCampId(), placeId)) {
            return GameErrorCode.E_XIU_XIAN_PLACE_USER_LIMIT;
        }
        if (!isBirthPlace(placeId)) {
            // 死亡状态只允许回出生点且不读cd
            if (pvpUserData.getUserState() == 1) {
                return GameErrorCode.E_XIU_XIAN_PVP_ONLY_GO_TO_BIRTH;
            }
            // 非死亡状态
            long nowTime = System.currentTimeMillis();
            if (nowTime < pvpUserData.getTransferTime()) {
                // 没到传送时间
                return GameErrorCode.E_XIU_XIAN_PVP_DONT_TRANSFER;
            }
            // 传送时间
            pvpUserData.setTransferTime(nowTime + DateHelper.SECOND_MILLIONS * config.getXIUXIAN_PVP_DELIVERY_CD());
        } else {
            // 如果是死亡状态，处理下复活
            if (pvpUserData.getUserState() == 1) {
                revive(pvpUserData);
            }
        }
        // 离开旧房间
        leavePlace(pvpUserData, 4);
        // 加入房间
        joinPlace(placeId, pvpUserData);
        XiuXianProto.XiuXianEnterPlaceRespMsg.Builder builder = XiuXianProto.XiuXianEnterPlaceRespMsg.newBuilder();
        builder.setRet(0);
        XiuXianProto.XiuXianPvpPlaceInfoTemp.Builder placeInfoTemp = parseXiuXianPvpPlaceInfoTemp(getPvpPlace(pvpUserData.getPlaceId()));
        if (placeInfoTemp != null) {
            builder.setPlace(placeInfoTemp);
        }
        builder.setPlaceId(placeId);
        builder.setTransferTime(pvpUserData.getTransferTime());
        sendPacket(ClientProtocol.U_XIU_XIAN_ENTER_PLACE, builder, userId);
        return 0;
    }

    /**
     * 离开房间Cmd
     *
     * @param userId 玩家id
     */
    public int leavePlaceByCmd(long userId) {
        if (!isAble(userId)) {
            return GameErrorCode.E_XIU_XIAN_PVP_NO_ABLE;
        }
        CrossXiuXianPvpUserData pvpUserData = getPvpUserData(userId);
        if (pvpUserData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        // 离开房间
        leavePlace(pvpUserData, 1);
        XiuXianProto.XiuXianLeavePlaceRespMsg.Builder builder = XiuXianProto.XiuXianLeavePlaceRespMsg.newBuilder();
        builder.setRet(0);
        sendPacket(ClientProtocol.U_XIU_XIAN_LEAVE_PLACE, builder, userId);
        return 0;
    }

    public int getActivityData(long userId) {
        // 回游戏服
        XiuXianProto.CrossXiuXianPvpActivityDataSync.Builder builder = XiuXianProto.CrossXiuXianPvpActivityDataSync.newBuilder();
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setRound(getCurRound());
        builder.setState(crossXiuXianPvpData.getActivityState());
        sendPacket(GameProtocol.S_CROSS_XIU_XIAN_GET_ACTIVITY_DATA, builder, userId);
        return 0;
    }

    /**
     * 获取PVP结束信息
     */
    public int getPvpEndData(long userId, int endRound) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        XiuXianProto.CrossXiuXianPvpEndDataRespMsg.Builder builder = XiuXianProto.CrossXiuXianPvpEndDataRespMsg.newBuilder();
        // 当前可展示场次
        int curRound = getCurRound();
        // 获取从结算场次到当前场次的战绩
        int resultEndRound = endRound;
        // endRound已结算过，跳过，+1开始
        for (int round = endRound + 1; round <= curRound; round++) {
            if (!endRecordMap.containsKey(round) || !crossXiuXianPvpData.getCampScoreRecordMap().containsKey(round)) {
                // 空的轮次且场次小于当前轮次当做已结算
                if (round < curRound) {
                    resultEndRound = round;
                }
                if (round == curRound && crossXiuXianPvpData.getActivityState() == eXiuXianPvpActivityStateType.End.getValue()) {
                    resultEndRound = round;
                }
                continue;
            }
            // 这个要传回游戏服给用户
            resultEndRound = round;
            CrossXiuXianPvpEndRecord endRecord = endRecordMap.get(round);
            XiuXianProto.XiuXianPvpEndDataTemp.Builder temp = XiuXianProto.XiuXianPvpEndDataTemp.newBuilder();
            temp.setRound(round);
            // 个人战绩
            temp.setBattleScore(parseXiuXianPvpBattleScoreTemp(userData.getBattleRecordMap().get(round)));
            // 宗门积分
            Map<Integer, CrossXiuXianPvpCampScoreRecord> scoreRecordMap = crossXiuXianPvpData.getCampScoreRecordMap().get(round);
            if (scoreRecordMap == null) {
                continue;
            }
            for (CrossXiuXianPvpCampScoreRecord campScoreRecord : scoreRecordMap.values()) {
                XiuXianProto.XiuXianCampScoreTemp.Builder campScoreTemp = XiuXianProto.XiuXianCampScoreTemp.newBuilder();
                campScoreTemp.setCampId(campScoreRecord.getCampId());
                campScoreTemp.setScore(campScoreRecord.getScore());
                campScoreTemp.setRank(campScoreRecord.getRank());
                // 宗门总积分
                int rankNum = 0;
                for (CrossXiuXianRank rank : campTotalScoreRankMap.getRankList()) {
                    ++rankNum;
                    if (campScoreRecord.getCampId() == Integer.parseInt(rank.getId())) {
                        campScoreTemp.setTotalScore(rank.getValue());
                        campScoreTemp.setTotalRank(rankNum);
                    }
                }
                temp.addCampScore(campScoreTemp);
            }
            // 本轮最佳表现
            XiuXianProto.XiuXianPvpBestPerformanceTemp.Builder bestPerformanceTemp = XiuXianProto.XiuXianPvpBestPerformanceTemp.newBuilder();
            // 本轮最佳抢点王
            CrossXiuXianPvpBestBattleRecord bestSeizeUser = endRecord.getBestSeizeUser();
            if (bestSeizeUser != null && bestSeizeUser.getUserId() != 0) {
                XiuXianProto.XiuXianPvpBattleScoreUserTemp.Builder seizeUserTemp = XiuXianProto.XiuXianPvpBattleScoreUserTemp.newBuilder();
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(bestSeizeUser.getUserId());
                if (userBaseInfo != null) {
                    seizeUserTemp.setUserId(bestSeizeUser.getUserId());
                    seizeUserTemp.setUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    // 战绩
                    XiuXianProto.XiuXianPvpBattleScoreTemp.Builder battleScoreTemp = XiuXianProto.XiuXianPvpBattleScoreTemp.newBuilder();
                    battleScoreTemp.setKill(bestSeizeUser.getBattleRecord().getKill());
                    battleScoreTemp.setKillScore(bestSeizeUser.getBattleRecord().getKillScore());
                    battleScoreTemp.setSeize(bestSeizeUser.getBattleRecord().getSeize());
                    battleScoreTemp.setSeizeScore(bestSeizeUser.getBattleRecord().getSeizeScore());
                    seizeUserTemp.setScore(battleScoreTemp);
                    // 宗门id
                    seizeUserTemp.setCampId(bestSeizeUser.getCampId());
                    bestPerformanceTemp.setSeize(seizeUserTemp);
                }
            }
            // 本轮最佳击杀王
            CrossXiuXianPvpBestBattleRecord bestKillUser = endRecord.getBestKillUser();
            if (bestKillUser != null && bestKillUser.getUserId() != 0) {
                XiuXianProto.XiuXianPvpBattleScoreUserTemp.Builder killUserTemp = XiuXianProto.XiuXianPvpBattleScoreUserTemp.newBuilder();
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(bestKillUser.getUserId());
                if (userBaseInfo != null) {
                    killUserTemp.setUserId(bestKillUser.getUserId());
                    killUserTemp.setUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    // 战绩
                    XiuXianProto.XiuXianPvpBattleScoreTemp.Builder battleScoreTemp = XiuXianProto.XiuXianPvpBattleScoreTemp.newBuilder();
                    battleScoreTemp.setKill(bestKillUser.getBattleRecord().getKill());
                    battleScoreTemp.setKillScore(bestKillUser.getBattleRecord().getKillScore());
                    battleScoreTemp.setSeize(bestKillUser.getBattleRecord().getSeize());
                    battleScoreTemp.setSeizeScore(bestKillUser.getBattleRecord().getSeizeScore());
                    killUserTemp.setScore(battleScoreTemp);
                    // 宗门id
                    killUserTemp.setCampId(bestKillUser.getCampId());
                    bestPerformanceTemp.setKill(killUserTemp);
                }
            }
            temp.setBestPerformance(bestPerformanceTemp);

            // 宗门最佳表现
            XiuXianProto.XiuXianPvpBestPerformanceTemp.Builder campBestPerformanceTemp = XiuXianProto.XiuXianPvpBestPerformanceTemp.newBuilder();
            // 我的宗门
            int myCampId = getCampByUserId(userId);
            // 宗门最佳抢点王
            CrossXiuXianPvpBestBattleRecord campBestSeizeUser = endRecord.getCampBestSeizeUserMap().get(myCampId);
            if (campBestSeizeUser != null && campBestSeizeUser.getUserId() != 0) {
                XiuXianProto.XiuXianPvpBattleScoreUserTemp.Builder campSeizeUserTemp = XiuXianProto.XiuXianPvpBattleScoreUserTemp.newBuilder();
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(campBestSeizeUser.getUserId());
                if (userBaseInfo != null) {
                    campSeizeUserTemp.setUserId(campBestSeizeUser.getUserId());
                    campSeizeUserTemp.setUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    // 战绩
                    XiuXianProto.XiuXianPvpBattleScoreTemp.Builder battleScoreTemp = XiuXianProto.XiuXianPvpBattleScoreTemp.newBuilder();
                    battleScoreTemp.setKill(campBestSeizeUser.getBattleRecord().getKill());
                    battleScoreTemp.setKillScore(campBestSeizeUser.getBattleRecord().getKillScore());
                    battleScoreTemp.setSeize(campBestSeizeUser.getBattleRecord().getSeize());
                    battleScoreTemp.setSeizeScore(campBestSeizeUser.getBattleRecord().getSeizeScore());
                    campSeizeUserTemp.setScore(battleScoreTemp);
                    // 宗门id
                    campSeizeUserTemp.setCampId(campBestSeizeUser.getCampId());
                    campBestPerformanceTemp.setSeize(campSeizeUserTemp);
                }
            }
            // 宗门最佳击杀王
            CrossXiuXianPvpBestBattleRecord campBestKillUser = endRecord.getCampBestKillUserMap().get(myCampId);
            if (campBestKillUser != null && campBestKillUser.getUserId() != 0) {
                XiuXianProto.XiuXianPvpBattleScoreUserTemp.Builder campKillUserTemp = XiuXianProto.XiuXianPvpBattleScoreUserTemp.newBuilder();
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(campBestKillUser.getUserId());
                if (userBaseInfo != null) {
                    campKillUserTemp.setUserId(campBestKillUser.getUserId());
                    campKillUserTemp.setUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    // 战绩
                    XiuXianProto.XiuXianPvpBattleScoreTemp.Builder battleScoreTemp = XiuXianProto.XiuXianPvpBattleScoreTemp.newBuilder();
                    battleScoreTemp.setKill(campBestKillUser.getBattleRecord().getKill());
                    battleScoreTemp.setKillScore(campBestKillUser.getBattleRecord().getKillScore());
                    battleScoreTemp.setSeize(campBestKillUser.getBattleRecord().getSeize());
                    battleScoreTemp.setSeizeScore(campBestKillUser.getBattleRecord().getSeizeScore());
                    campKillUserTemp.setScore(battleScoreTemp);
                    // 宗门id
                    campKillUserTemp.setCampId(campBestKillUser.getCampId());
                    campBestPerformanceTemp.setKill(campKillUserTemp);
                }
            }
            temp.setCampBestPerformance(campBestPerformanceTemp);
            // 获取个人战绩
            // 排名
            int userRankNum = 0;
            long userScore = 0;
            boolean find = false;
            for (CrossXiuXianRank rank : userScoreRank.getRankList()) {
                ++userRankNum;
                if (rank.getId().equals(String.valueOf(userId))) {
                    userScore = rank.getValue();
                    find = true;
                    break;
                }
            }
            // 没找到排名为-1
            temp.setRank(find ? userRankNum : -1);
            temp.setScore(userScore);
            builder.addEndData(temp);
        }
        builder.setEndRound(resultEndRound);
        // 传回游戏服
        sendPacket(GameProtocol.S_CROSS_XIU_XIAN_GET_PVP_END_DATA, builder, userId);
        return 0;
    }


    /**
     * 移动
     *
     * @param userId   玩家id
     * @param position 位置信息
     */
    public int moveByCmd(long userId, CrossXiuXianPvpPosition position) {
        if (!isAble(userId)) {
            return GameErrorCode.E_XIU_XIAN_PVP_NO_ABLE;
        }
        CrossXiuXianPvpUserData pvpUserData = getPvpUserData(userId);
        if (pvpUserData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        if (!isBirthPlace(pvpUserData.getPlaceId()) && pvpUserData.getUserState() == 1) {
            return GameErrorCode.E_XIU_XIAN_PVP_DIE;
        }
        // 移动
        move(pvpUserData, position);
        XiuXianProto.XiuXianMoveRespMsg.Builder builder = XiuXianProto.XiuXianMoveRespMsg.newBuilder();
        builder.setRet(0);
        sendPacket(ClientProtocol.U_XIU_XIAN_MOVE, builder, userId);
        return 0;
    }


    /**
     * 攻击
     */
    public int attackByCmd(long userId, long attackedUserId) {
        if (!isAble(userId) || !isAble(attackedUserId)) {
            return GameErrorCode.E_XIU_XIAN_PVP_NO_ABLE;
        }
        long nowTime = System.currentTimeMillis();
        CrossXiuXianPvpUserData userData;
        // 获取被攻击人的信息
        long leftHp;
        int stageId;
        CrossXiuXianPvpAttackHelper attackHelper;
        int placeId;
        userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        if (userData.getUserState() == 1) {
            return GameErrorCode.E_XIU_XIAN_PVP_DIE;
        }
        // 攻速
        long atkSpeed = userData.getPvpProperty().getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.AtkSpeed.getValue(), 1000L);
        // 攻速千分比 区间只能1-1000  程序做个保护
        int speedRatio = Math.max(1, Math.min(1000, config.getXIUXIAN_PVP_ATTACK_SPEED_RATIO()));
        // 算下一秒攻击多少下  最低0.5,最大5下，特殊处理下 程序做个保护
        double atkCount = Math.min(5, Math.max(0.5, BigDecimal.valueOf(atkSpeed).divide(BigDecimal.valueOf(1000), 8, BigDecimal.ROUND_DOWN).multiply(BigDecimal.valueOf(speedRatio)).divide(BigDecimal.valueOf(1000), 8, BigDecimal.ROUND_DOWN).doubleValue()));
        // 攻击间隔
        long atkTime = BigDecimal.valueOf(1000).divide(BigDecimal.valueOf(atkCount), 0, BigDecimal.ROUND_UP).longValue();
        if (nowTime - userData.getAttackTime() < atkTime) {
            return GameErrorCode.E_XIU_XIAN_ATTACK_TIME_LIMIT;
        }
        placeId = userData.getPlaceId();
        // 打架获取房间锁
        synchronized (getPlaceLock(placeId)) {
            // 被攻击者
            CrossXiuXianPvpUserData attackedUserData = getPvpUserData(attackedUserId);
            if (attackedUserData == null) {
                return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
            }
            XiuXianPvpUserProperty attackedProperty = attackedUserData.getPvpProperty();
            // 判断是否能攻击
            if (attackedProperty.getHp() == 0) {
                return GameErrorCode.E_XIU_XIAN_TARGET_NOT_FOUND;
            }
            if (attackedUserData.getPlaceId() != placeId) {
                return GameErrorCode.E_XIU_XIAN_TARGET_NOT_FOUND;
            }
            if (attackedUserData.getCampId() == userData.getCampId()) {
                return GameErrorCode.E_XIU_XIAN_DONT_ATTACK_THE_SAME_CAMP;
            }
            stageId = attackedProperty.getStateId();
            // 攻击
            attackHelper = attack(placeId, userData, attackedUserData);
            // 被打同步消息
            syncAttackedUser(userData, attackedUserData, attackHelper);
            // 记录一下攻击时间
            userData.setAttackTime(nowTime);
            leftHp = attackHelper.getAttackedHp();
        }

        long attackScore = 0;
        // 成功击杀
        if (leftHp == 0) {
            // 检测占领时间
            checkPlaceSeizeTime(placeId, true);

            // 成功击杀同步房间被打记录
            syncPlaceAttack(placeId);

            // 攻击得分 被击杀者仙力值×参数
            List<String> scoreParamList = StringUtils.stringToStringList(config.getXIUXIAN_PVP_PERSONAL_SCORE_KILL(), "\\|");
            for (String param : scoreParamList) {
                String[] split = param.split(";");
                if (stageId >= Integer.parseInt(split[0])) {
                    attackScore = Long.parseLong(split[1]);
                }
            }
            // 记录战绩
            addBattleScore(userId, 1, attackScore, String.valueOf(attackedUserId));
            // 判断下击杀是否满足单条命推送公告
            List<String> noticeParamList = StringUtils.stringToStringList(config.getXIUXIAN_PVP_NOTICE_SINGLE_TIME_KILL_NUM(), "\\|");
            String params = noticeParamList.get(1);
            List<Integer> paramList = StringUtils.stringToIntegerList(params, ";");
            int curRound = getCurRound();
            int killNum = userData.getBattleRecord().getKill();
            if (paramList.contains(killNum)) {
                // 添加单条命击杀公告
                CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
                noticeData.setActivityId(config.getActivityInfo().getActivityId());
                noticeData.setRound(curRound);
                noticeData.setCampId(userData.getCampId());
                noticeData.setNoticeType(eXiuXianPvpNoticeType.Kill.getValue());
                noticeData.setContent(String.valueOf(killNum));
                noticeData.setNoticeTime(nowTime);
                noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
                addPvpNoticeData(noticeData, userData.getUserId(), 0);
            }
            // 判断下击杀是否满足单轮推送公告
            List<String> noticeParamList1 = StringUtils.stringToStringList(config.getXIUXIAN_PVP_NOTICE_SINGLE_WHEEL_KILL_NUM(), "\\|");
            String params1 = noticeParamList1.get(1);
            List<Integer> paramList1 = StringUtils.stringToIntegerList(params1, ";");
            int roundKillNum = 0;
            if (userData.getBattleRecordMap().containsKey(curRound)) {
                roundKillNum = userData.getBattleRecordMap().get(curRound).getKill();
            }
            if (paramList1.contains(roundKillNum)) {
                // 添加本轮斗法累计击杀公告
                CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
                noticeData.setActivityId(config.getActivityInfo().getActivityId());
                noticeData.setRound(curRound);
                noticeData.setCampId(userData.getCampId());
                noticeData.setNoticeType(eXiuXianPvpNoticeType.TotalKill.getValue());
                noticeData.setContent(String.valueOf(roundKillNum));
                noticeData.setNoticeTime(nowTime);
                noticeData.setIsRoll(Integer.parseInt(noticeParamList1.get(0)));
                addPvpNoticeData(noticeData, userData.getUserId(), 0);
            }
        }

        XiuXianProto.XiuXianAttackRespMsg.Builder builder = XiuXianProto.XiuXianAttackRespMsg.newBuilder();
        builder.setRet(0);
        builder.setAttackTime(nowTime);
        builder.setAttack(parseXiuXianAttackedTemp(attackHelper));
        builder.setAttackScore(attackScore);
        sendPacket(ClientProtocol.U_XIU_XIAN_ATTACK, builder, userId);
        return 0;
    }

    /**
     * 攻击
     *
     * @param placeId      房间id
     * @param attackUser   攻击者
     * @param attackedUser 被攻击者
     */
    public CrossXiuXianPvpAttackHelper attack(int placeId, CrossXiuXianPvpUserData attackUser, CrossXiuXianPvpUserData attackedUser) {
        // 添加攻击记录
        CrossXiuXianPvpAttackHelper attackHelper = new CrossXiuXianPvpAttackHelper();
        attackHelper.setAttackUserId(attackUser.getUserId());
        attackHelper.setAttackedUserId(attackedUser.getUserId());
        XiuXianPvpUserProperty attackedProperty = attackedUser.getPvpProperty();
        XiuXianPvpUserProperty attackProperty = attackUser.getPvpProperty();
        // 攻击逻辑
        // 先判断是否能闪避本次攻击
        // 闪避几率 = (对方闪避值千分数 - 我方命中值千分数) / 1000
        long dodgeValue = attackedProperty.getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.DodgeRatio.getValue(), 0L) - attackProperty.getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.HitRatio.getValue(), 0L);
        if(dodgeValue > config.getXIUXIAN_MAX_SHANBI_SHANGXIAN()){
            dodgeValue = config.getXIUXIAN_MAX_SHANBI_SHANGXIAN();
        }
        boolean isDodge = randomHelper.next(0, 1000) < Math.max(0, dodgeValue);
        if (!isDodge) {
            // 没闪避才继续往下处理
            // 暴击几率 = (我方暴击值千分数 - 对方坚韧值千分数) / 1000
            boolean isCrit = randomHelper.next(0, 1000) < Math.max(0, attackProperty.getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.CritRatio.getValue(), 0L) - attackedProperty.getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.TenacityRatio.getValue(), 0L));
            long attackHp = attackProperty.getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.Atk.getValue(), 0L);
            if (isCrit) {
                attackHp *= 2;
            }
            attackHp = Math.min(attackHp, attackedProperty.getHp());
            // 扣血
            attackedProperty.setHp(attackedProperty.getHp() - attackHp);
            // 吸血
            long suckHp = Math.min(attackProperty.getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.Hp.getValue(), 0L) - attackProperty.getHp(), BigDecimal.valueOf(attackHp).multiply(BigDecimal.valueOf(attackProperty.getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.SuckRatio.getValue(), 0L))).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_DOWN).longValue());
            // 加血
            attackProperty.setHp(attackProperty.getHp() + suckHp);
            attackHelper.setCrit(isCrit);
            attackHelper.setHp(attackHp);
            attackHelper.setSuckHp(suckHp);
        }
        attackUser.setPvpProperty(attackProperty);
        attackedUser.setPvpProperty(attackedProperty);
        attackHelper.setDodge(isDodge);
        attackHelper.setAttackHp(attackProperty.getHp());
        attackHelper.setAttackedHp(attackedProperty.getHp());
        addPvpAttackSyncData(placeId, attackHelper);
        return attackHelper;
    }

    public long calcTotalScore(CrossXiuXianPvpUserData userData) {
        if (userData == null) {
            return 0;
        }
        return userData.getAttackScore() + userData.getSeizeScore();
    }

    private boolean isNpc(long userId) {
        return npcUserMap.containsKey(userId) && npcDataMap.containsKey(userId);
    }

    /**
     * 增加击杀战绩
     *
     * @param type 1 击杀战绩 2 占领战绩
     * @param param type1 传被击杀者id
     */
    public void addBattleScore(long userId, int type, long addScore, String param) {
//        if (isNpc(userId)) {
//            // npc不推公告，不记录战绩了
//            return;
//        }
        int curRound = getCurRound();
        // 获取可推送档次
        long canNoticeScoreLevel = -1;
        long oldTotalScore;
        long newTotalScore;
        CrossXiuXianPvpUserData userData;
        synchronized (getPlayerLock(userId)) {
            userData = getPvpUserData(userId);
            oldTotalScore = calcTotalScore(userData);
            // 本条命战绩
            CrossXiuXianPvpBattleRecord battleRecord = userData.getBattleRecord();
            if (type == 1) {
                battleRecord.setKill(battleRecord.getKill() + 1);
                battleRecord.setKillScore(battleRecord.getKillScore() + addScore);
                userData.setAttackScore(userData.getAttackScore() + addScore);
            } else if (type == 2) {
                battleRecord.setSeize(battleRecord.getSeize() + 1);
                battleRecord.setSeizeScore(battleRecord.getSeizeScore() + addScore);
                userData.setSeizeScore(userData.getSeizeScore() + addScore);
            }
            userData.setUpdateScoreTime(System.currentTimeMillis());
            userData.setBattleRecord(battleRecord);
            // 加入历史战绩,本轮战绩
            Map<Integer, CrossXiuXianPvpBattleRecord> battleRecordMap = userData.getBattleRecordMap();
            if (!battleRecordMap.containsKey(curRound)) {
                battleRecordMap.put(curRound, new CrossXiuXianPvpBattleRecord());
            }
            CrossXiuXianPvpBattleRecord roundBattleRecord = battleRecordMap.get(curRound);
            if (type == 1) {
                roundBattleRecord.setKill(roundBattleRecord.getKill() + 1);
                roundBattleRecord.setKillScore(roundBattleRecord.getKillScore() + addScore);
            } else if (type == 2) {
                roundBattleRecord.setSeize(roundBattleRecord.getSeize() + 1);
                roundBattleRecord.setSeizeScore(roundBattleRecord.getSeizeScore() + addScore);
            }
            battleRecordMap.put(curRound, roundBattleRecord);
            userData.setBattleRecordMap(battleRecordMap);
            newTotalScore = calcTotalScore(userData);
        }

        // 战绩榜
        if (!isNpc(userId) && newTotalScore > 0) {
            userScoreRank.rankChange(new CrossXiuXianRank(String.valueOf(userData.getUserId()), newTotalScore, userData.getUpdateScoreTime()));
        }

        if (type == 1) {
            // 判断下单次击杀获得的战绩是否推送
            List<String> noticeParamList = StringUtils.stringToStringList(config.getXIUXIAN_PVP_NOTICE_SINGLE_PERSONAL_SCORE(), "\\|");
            int noticeStateId = Integer.parseInt(noticeParamList.get(1));
            // 境界是否包含
            CrossXiuXianPvpUserData attackedUserData = getPvpUserData(Long.parseLong(param));
            if (attackedUserData != null && attackedUserData.getPveProperty().getStateId() >= noticeStateId) {
                // 添加公告
                CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
                noticeData.setActivityId(config.getActivityInfo().getActivityId());
                noticeData.setRound(curRound);
                noticeData.setCampId(userData.getCampId());
                noticeData.setNoticeType(eXiuXianPvpNoticeType.killScore.getValue());
                noticeData.setContent(addScore + "#" + attackedUserData.getCampId());
                noticeData.setNoticeTime(System.currentTimeMillis());
                noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
                addPvpNoticeData(noticeData, userData.getUserId(), attackedUserData.getUserId());
            }
            if (!isNpc(userId)) {
                // 通知游戏服更新condition成就
                notifyConditionChange(userData.getUserId(), eGamePlayerEventType.XiuXianAttackScore, userData.getAttackScore());
            }
        }

        // 判断下个人战绩是否推送
        List<String> noticeParamList = StringUtils.stringToStringList(config.getXIUXIAN_PVP_NOTICE_PERSONAL_SCORE(), "\\|");
        String params = noticeParamList.get(1);
        List<Integer> paramList = StringUtils.stringToIntegerList(params, ";");
        for (int score : paramList) {
            if (score > oldTotalScore && score <= newTotalScore) {
                canNoticeScoreLevel = score;
            }
        }
        if (canNoticeScoreLevel >= 0) {
            // 添加公告
            CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
            noticeData.setActivityId(config.getActivityInfo().getActivityId());
            noticeData.setRound(curRound);
            noticeData.setCampId(userData.getCampId());
            noticeData.setNoticeType(eXiuXianPvpNoticeType.TotalScore.getValue());
            noticeData.setContent(String.valueOf(canNoticeScoreLevel));
            noticeData.setNoticeTime(System.currentTimeMillis());
            noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
            addPvpNoticeData(noticeData, userData.getUserId(), 0);
        }

    }
    /**
     * 历练地图界面同步操作
     */
    public void syncPracticeMenuOp(int opType, long userId, CrossXiuXianPvpUserData userData) {
        if (practiceUserSet.size() == 0) {
            return;
        }
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if (null == userBaseInfo) {
            return;
        }
        // 同步给房间的用户
        XiuXianProto.XiuXianPracticeMenuOpSyncMsg.Builder syncMsg = XiuXianProto.XiuXianPracticeMenuOpSyncMsg.newBuilder();
        XiuXianProto.PracticeMenuOpInfoTemp.Builder tempMsg = XiuXianProto.PracticeMenuOpInfoTemp.newBuilder();
        tempMsg.setOpType(opType);
        tempMsg.setUserId(userId);
        if (opType == 1) {
            tempMsg.setUserInfo(CrossXiuXianPb.parsePveSampleTemp(userBaseInfo, userData));
        }
        syncMsg.addOpInfoList(tempMsg);
        sendPacketToAll(ClientProtocol.U_XIU_XIAN_PRACTICE_MENU_OP_SYNC, syncMsg, practiceUserSet);
    }

    /**
     * 进入历练地图
     *
     * @param userId 玩家id
     */
    public int enterPracticeByCmd(long userId) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        synchronized (practiceUserSet) {
            // 限制人数
            if (practiceUserSet.size() < config.getXIUXIAN_PRACTICE_MENU_NUM() || practiceUserSet.contains(userId)) {
                // 同步玩家进入
                syncPracticeMenuOp(1, userId, userData);
                practiceUserSet.add(userId);
            }
        }
        // 返回给进入玩家
        XiuXianProto.XiuXianEnterPracticeMenuRespMsg.Builder builder = XiuXianProto.XiuXianEnterPracticeMenuRespMsg.newBuilder();
        builder.setRet(0);
        for (long tempUserId : practiceUserSet) {
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(tempUserId);
            CrossXiuXianPvpUserData otherUserData = getPvpUserData(tempUserId);
            if (null == userBaseInfo || null == otherUserData || tempUserId == userId) {
                continue;
            }
            builder.addOtherUserList(CrossXiuXianPb.parsePveSampleTemp(userBaseInfo, otherUserData));
        }
        sendPacket(ClientProtocol.U_XIU_XIAN_ENTER_PRACTICE_MENU, builder, userId);
        return 0;
    }

    /**
     * 离开历练地图
     *
     * @param userId 玩家id
     */
    public void leavePracticeByCmd(long userId) {
        boolean isInRoom = false;
        synchronized (practiceUserSet) {
            if (practiceUserSet.contains(userId)) {
                isInRoom = true;
                practiceUserSet.remove(userId);
            }
        }
        if (isInRoom) {
            // 同步玩家离开
            syncPracticeMenuOp(2, userId, null);
        }
        return;
    }
    /**
     * 获取宗门房间
     */
    public void buildMountInfoTemp(XiuXianProto.XiuXianGetMountInfoRespMsg.Builder builder, int sectId) {
        Map<Integer, Map<Integer, List<Long>>> mountRoomMap = campMountRoomMap.get(sectId);
        if (mountRoomMap == null) {
            return;
        }
        // 获取配置并排序
        List<Integer> peakIdList = new ArrayList<>(config.getPeakConfigMap().keySet());
        Collections.sort(peakIdList);
        int mountStartRank = 0;
        for (Integer mountId : peakIdList) {
            // 是否有数据、或者是否是默认灵峰
            if (!mountRoomMap.containsKey(mountId) || mountId == config.getDefaultMount()) {
                break;
            }
            XiuXianPeakConfig peakConfig = config.getPeakConfigMap().get(mountId);

            XiuXianProto.MountInfoTemp.Builder mountInfoTemp = XiuXianProto.MountInfoTemp.newBuilder();
            mountInfoTemp.setMountId(mountId);
            Map<Integer, List<Long>> roomMap = mountRoomMap.get(mountId);
            for(Map.Entry<Integer, List<Long>> subEntry : roomMap.entrySet()) {
                XiuXianProto.MountRoomInfoTemp.Builder roomInfoTemp = XiuXianProto.MountRoomInfoTemp.newBuilder();
                int roomId = subEntry.getKey();
                roomInfoTemp.setRoomId(roomId);
                roomInfoTemp.setStartRank(mountStartRank + (roomId - 1) * peakConfig.getPeopleNum() + 1);
                roomInfoTemp.setEndRank(mountStartRank + roomId * peakConfig.getPeopleNum());
                mountInfoTemp.addRoomList(roomInfoTemp);
            }
            mountStartRank += peakConfig.getRoomNum() * peakConfig.getPeopleNum();
            builder.addMountInfoList(mountInfoTemp);
        }
    }
    /**
     * 获取灵峰信息
     *
     * @param userId 玩家id
     */
    public int getMountInfoByCmd(long userId) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        XiuXianProto.XiuXianGetMountInfoRespMsg.Builder builder = XiuXianProto.XiuXianGetMountInfoRespMsg.newBuilder();
        builder.setRet(0);
        // 添加房间信息
        buildMountInfoTemp(builder, userData.getCampId());

        sendPacket(ClientProtocol.U_XIU_XIAN_GET_MOUNT_INFO, builder, userId);
        return 0;
    }
    /**
     * 获取下一次分配时间
     */
    private long getNextAllotTime() {
        return getCurAllotTime() + config.getXIUXIAN_PEAK_ASSIGN_CD();
    }

    /**
     * 获取下一次分配时间
     */
    private long getNextAllotTime(long time) {
        return getCurAllotTime(time) + config.getXIUXIAN_PEAK_ASSIGN_CD();
    }

    /**
     * 获取当前分配时间 假设时间是0点01分 这边取到的时间是当前这一分配期的标识
     */
    private long getCurAllotTime(long time) {
        long nowTime = time / 1000;
        int allotCount = (int)Math.floor((double)(nowTime - config.getActivityInfo().getBeginTime()) / config.getXIUXIAN_PEAK_ASSIGN_CD());
        // 当前的
        long tempAllotTimeId = config.getActivityInfo().getBeginTime() + allotCount * config.getXIUXIAN_PEAK_ASSIGN_CD();
        if (tempAllotTimeId < config.getActivityInfo().getBeginTime()) {
            tempAllotTimeId = config.getActivityInfo().getBeginTime();
        }
        return tempAllotTimeId;
    }


    /**
     * 获取当前分配时间
     */
    private long getCurAllotTime() {
        long nowTime = System.currentTimeMillis() / 1000;
        int allotCount = (int)Math.floor((double)(nowTime - config.getActivityInfo().getBeginTime()) / config.getXIUXIAN_PEAK_ASSIGN_CD());
        // 当前的
        long tempAllotTimeId = config.getActivityInfo().getBeginTime() + allotCount * config.getXIUXIAN_PEAK_ASSIGN_CD();
        if (tempAllotTimeId < config.getActivityInfo().getBeginTime()) {
            tempAllotTimeId = config.getActivityInfo().getBeginTime();
        }
        return tempAllotTimeId;
    }

    /**
     * 构造默认的房间信息
     */
    private XiuXianRoomMemberInfo buildDefaultRoomInfo(long allotId) {
        XiuXianRoomMemberInfo curMountInfo = new XiuXianRoomMemberInfo();
        curMountInfo.setMountId(config.getDefaultMount());
        curMountInfo.setRoomId(1);
        curMountInfo.setRank(-1);
        curMountInfo.setPosId(1);
        curMountInfo.setId(allotId);
        return curMountInfo;
    }

    /**
     * 获取当前的房间信息
     */
    private XiuXianRoomMemberInfo getDetailRoomInfo(CrossXiuXianPvpUserData userData, long allotId) {
        XiuXianRoomMemberInfo curMountInfo;
        if (allotId == 0) {
            // 未有房间信息、构造一个默认的
            curMountInfo = buildDefaultRoomInfo(allotId);
        } else {
            curMountInfo = userData.getMountData().getAllAllotMap().get(allotId);
            if (curMountInfo == null) {
                curMountInfo = buildDefaultRoomInfo(allotId);
            }
        }
        return curMountInfo;
    }
    /**
     * 封装灵峰变更模板
     */
    public static XiuXianProto.MountChangeInfoTemp.Builder parseMountChangeInfoTemp(XiuXianRoomMemberInfo roomMemberInfo) {
        XiuXianProto.MountChangeInfoTemp.Builder changeInfoTemp = XiuXianProto.MountChangeInfoTemp.newBuilder();
        changeInfoTemp.setSectRank(roomMemberInfo.getRank());
        changeInfoTemp.setMountId(roomMemberInfo.getMountId());
        changeInfoTemp.setRoomId(roomMemberInfo.getRoomId());
        changeInfoTemp.setChangeTime(roomMemberInfo.getId());
        changeInfoTemp.setPosId(roomMemberInfo.getPosId());
        return changeInfoTemp;
    }
    /**
     * 进入宗门灵峰
     *
     * @param userId 玩家id
     */
    public int enterSectMountByCmd(long userId) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        CrossXiuXianUserMountData userMountData = userData.getMountData();
        // 当前灵峰信息
        XiuXianRoomMemberInfo curRoomInfo = getDetailRoomInfo(userData, userMountData.getNewId());
        int sectId = userData.getCampId();
        int mountId = curRoomInfo.getMountId();
        int roomId = curRoomInfo.getRoomId();
        // 上一次的灵峰id
        long lastAllotId = userMountData.getLastId();
        boolean isFirstEnter = userMountData.isNoEnter();
        userMountData.setLastId(userMountData.getNewId());
        userMountData.setNoEnter(false);
        userData.setMountData(userMountData);

        // 添加房间列表中
        checkRoomInPlayers(userId, sectId, mountId, roomId);

        // 返回给进入玩家
        XiuXianProto.XiuXianEnterSectMountRespMsg.Builder builder = XiuXianProto.XiuXianEnterSectMountRespMsg.newBuilder();
        builder.setRet(0);
        // 新旧下发变更
        if (userData.getMountData().getNewId() == lastAllotId || userData.getMountData().getLastId() == 0) {
            builder.setOldMountInfo(parseMountChangeInfoTemp(curRoomInfo));
            if (isFirstEnter) {
                // 首次进入下发一样的
                builder.setNewMountInfo(parseMountChangeInfoTemp(curRoomInfo));
            }
        } else {
            XiuXianRoomMemberInfo oldRoomInfo = getDetailRoomInfo(userData, lastAllotId);
            builder.setOldMountInfo(parseMountChangeInfoTemp(oldRoomInfo));
            builder.setNewMountInfo(parseMountChangeInfoTemp(curRoomInfo));
        }
        builder.setNextAllotTime(getNextAllotTime());
        builder.setIsFirstEnter(isFirstEnter);
        builder.addAllUserInfoList(buildRoomMember(sectId, mountId, roomId));
        sendPacket(ClientProtocol.U_XIU_XIAN_ENTER_SECT_MOUNT, builder, userId);
        return 0;
    }

    /**
     * 生成房间成员
     *
     */
    public List<XiuXianProto.XiuXianPveSampleTemp> buildRoomMember(int sectId, int mountId, int roomId) {
        List<XiuXianProto.XiuXianPveSampleTemp> list = new ArrayList<>();
        if (mountId == config.getDefaultMount()) {
            return list;
        }
        if (campMountRoomMap.containsKey(sectId) && campMountRoomMap.get(sectId).containsKey(mountId) && campMountRoomMap.get(sectId).get(mountId).containsKey(roomId)) {
            List<Long> memberList = campMountRoomMap.get(sectId).get(mountId).get(roomId);
            for (Long tempUserId : memberList) {
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(tempUserId);
                CrossXiuXianPvpUserData userData = getPvpUserData(tempUserId);
                if (userBaseInfo == null || userData == null) {
                    continue;
                }
                list.add(CrossXiuXianPb.parsePveSampleTemp(userBaseInfo, userData).build());
            }
        }
        return list;
    }
    /**
     * 进入其他灵峰房间
     */
    public int enterOtherSectMountByCmd(long userId, int mountId, int roomId) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        // 添加房间列表中
        checkRoomInPlayers(userId, userData.getCampId(), mountId, roomId);

        XiuXianProto.XiuXianEnterOtherSectMountRespMsg.Builder respMsg = XiuXianProto.XiuXianEnterOtherSectMountRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.addAllUserInfoList(buildRoomMember(userData.getCampId(), mountId, roomId));
        respMsg.setNextAllotTime(getNextAllotTime());
        sendPacket(ClientProtocol.U_XIU_XIAN_ENTER_OTHER_SECT_MOUNT, respMsg, userId);
        return 0;
    }

    /**
     * 离开宗门灵峰
     */
    public void leaveSectMountByCmd(long userId, int mountId, int roomId) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return;
        }
        // 离开房间列表中
        checkRoomOutPlayers(userId, userData.getCampId(), mountId, roomId);
    }

    /**
     * 添加到待发送
     */
    public void addRoomOp(int sectId, int mountId, int roomId, XiuXianRoomSyncData syncData) {
        // 过滤默认的灵峰
        if (config.getDefaultMount() == mountId) {
            return;
        }
        synchronized (changeRoomOpMap) {
            if (!changeRoomOpMap.containsKey(sectId)) {
                changeRoomOpMap.put(sectId, new ConcurrentHashMap<>());
            }
            if (!changeRoomOpMap.get(sectId).containsKey(mountId)) {
                changeRoomOpMap.get(sectId).put(mountId, new ConcurrentHashMap<>());
            }
            if (!changeRoomOpMap.get(sectId).get(mountId).containsKey(roomId)) {
                changeRoomOpMap.get(sectId).get(mountId).put(roomId, new ArrayList<>());
            }
            changeRoomOpMap.get(sectId).get(mountId).get(roomId).add(syncData);
        }
    }
    /**
     * 同步房间操作
     */
    public void syncSectMemberOpTask() {
        if (changeRoomOpMap.size() > 0) {
            Map<Integer, Map<Integer, Map<Integer, List<XiuXianRoomSyncData>>>> tempMap = new ConcurrentHashMap<>();
            synchronized (changeRoomOpMap) {
                tempMap.putAll(changeRoomOpMap);
                changeRoomOpMap.clear();
            }
            syncSectMemberOp(tempMap);
        }
    }

    /**
     * 同步灵峰房间操作
     *
     */
    public void syncSectMemberOp(Map<Integer, Map<Integer, Map<Integer, List<XiuXianRoomSyncData>>>> tempMap) {
        for (Map.Entry<Integer, Map<Integer, Map<Integer, List<XiuXianRoomSyncData>>>> sectMap: tempMap.entrySet()) {
            int sectId = sectMap.getKey();
            for (Map.Entry<Integer, Map<Integer, List<XiuXianRoomSyncData>>> mountMap : sectMap.getValue().entrySet()) {
                int mountId = mountMap.getKey();
                for (Map.Entry<Integer, List<XiuXianRoomSyncData>> roomMap : mountMap.getValue().entrySet()) {
                    int roomId = roomMap.getKey();
                    syncSectMemberOp(sectId, mountId, roomId, roomMap.getValue());
                }
            }
        }
    }
    /**
     * 同步灵峰房间操作
     *
     */
    public void syncSectMemberOp(int sectId, int mountId, int roomId, List<XiuXianRoomSyncData> dataList) {
        if (inRoomPlayers.containsKey(sectId)
                && inRoomPlayers.get(sectId).containsKey(mountId) && inRoomPlayers.get(sectId).get(mountId).containsKey(roomId)) {
            Set<Long> memberList = inRoomPlayers.get(sectId).get(mountId).get(roomId);
            XiuXianProto.XiuXianSectMemberOpSyncMsg.Builder respMsg = XiuXianProto.XiuXianSectMemberOpSyncMsg.newBuilder();
            for (XiuXianRoomSyncData dataRoom : dataList) {
                XiuXianProto.RoomMemberOpInfoTemp.Builder opTemp = XiuXianProto.RoomMemberOpInfoTemp.newBuilder();
                opTemp.setOpType(dataRoom.getOpType());
                opTemp.setOpArg(dataRoom.getOpArg());
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(dataRoom.getUserId());
                CrossXiuXianPvpUserData userData = getPvpUserData(dataRoom.getUserId());
                if (userBaseInfo == null || userData == null) {
                    continue;
                }
                opTemp.setUserInfo(CrossXiuXianPb.parsePveSampleTemp(userBaseInfo, userData));
                respMsg.addOpInfoList(opTemp);
            }
            sendPacketToAll(ClientProtocol.U_XIU_XIAN_SECT_MEMBER_OP_SYNC, respMsg, memberList);
        }
    }
    /**
     * 同步灵峰变更
     *
     */
    public void syncMountChangeInfo() {
        for (long tempUserId: userInRoomMap.keySet()) {
            CrossXiuXianPvpUserData userData = getPvpUserData(tempUserId);
            if (null == userData) {
                continue;
            }
            XiuXianProto.XiuXianMountChangeSyncMsg.Builder builder = XiuXianProto.XiuXianMountChangeSyncMsg.newBuilder();
            CrossXiuXianUserMountData userMountData = userData.getMountData();
            // 当前灵峰信息
            XiuXianRoomMemberInfo curRoomInfo = getDetailRoomInfo(userData, userMountData.getNewId());
            long lastAllotId = userMountData.getLastId();
            // 设置已经查看
            userMountData.setLastId(userMountData.getNewId());
            userData.setMountData(userMountData);
            // 新旧下发变更
            if (userData.getMountData().getNewId() == lastAllotId || userData.getMountData().getLastId() == 0) {
                builder.setOldMountInfo(parseMountChangeInfoTemp(curRoomInfo));
                builder.setNewMountInfo(parseMountChangeInfoTemp(curRoomInfo));
            } else {
                XiuXianRoomMemberInfo oldRoomInfo = getDetailRoomInfo(userData, userData.getMountData().getLastId());
                builder.setNewMountInfo(parseMountChangeInfoTemp(curRoomInfo));
                builder.setOldMountInfo(parseMountChangeInfoTemp(oldRoomInfo));
            }
            builder.setNextAllotTime(getNextAllotTime());
            sendPacket(ClientProtocol.U_XIU_XIAN_MOUNT_CHANGE_SYNC, builder, tempUserId);
        }
    }
    /**
     * 房间成员操作广播
     */
    public void roomMemberOpByCmd(long userId, int opType, int opArg) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return;
        }
        XiuXianRoomMemberInfo curRoomInfo = getDetailRoomInfo(userData, userData.getMountData().getNewId());
        if (curRoomInfo.getRoomId() == config.getDefaultMount()) {
            // 默认房间过滤掉
            return;
        }
        //  加入消息队列
        XiuXianRoomSyncData roomSyncData = new XiuXianRoomSyncData(userId, opType, opArg);
        addRoomOp(userData.getCampId(), curRoomInfo.getMountId(), curRoomInfo.getRoomId(), roomSyncData);
    }
    /**
     * 获取宗门体力贡献排行榜
     */
    public int getCampEnergyRankByCmd(long userId) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        int myRank = -1;
        String userIdStr = Long.toString(userId);

        int maxNum = config.getXIUXIAN_ENERGY_NOTICE_NUM();
        XiuXianProto.XiuXianEnergyRankListRespMsg.Builder builder = XiuXianProto.XiuXianEnergyRankListRespMsg.newBuilder();
        CrossXiuXianRankListModel model = campEnergyRankMap.get(userData.getCampId());
        if (model != null) {
            int num = 0;
            XiuXianProto.XiuXianRankTempMsg.Builder tempRank = XiuXianProto.XiuXianRankTempMsg.newBuilder();
            for (CrossXiuXianRank rankData : model.getRankList()) {
                tempRank.setUserId(Long.parseLong(rankData.getId()));
                tempRank.setParam(rankData.getParam());
                tempRank.setValue(Long.toString(rankData.getValue()));
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(tempRank.getUserId());
                if (userBaseInfo == null) {
                    continue;
                }
                PlayerProto.PlayerBaseTempMsg.Builder baseMsg = PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo);
                if(null != baseMsg) {
                    tempRank.setPlayerBaseData(baseMsg);
                }
                builder.addRankList(tempRank);
                num++;
                if (Objects.equals(rankData.getId(), userIdStr)) {
                    myRank = num;
                }
                if (num >= maxNum) {
                    break;
                }
            }
        }
        builder.setRet(0);
        builder.setValue(userData.getTotalUseEnergy());
        builder.setMyRank(myRank);
        sendPacket(ClientProtocol.U_XIU_XIAN_ENERGY_RANK_LIST, builder, userId);
        return 0;
    }

    /**
     * 使用体力同步
     */
    public void syncUseEnergyByCmd(long userId, int totalUseEnergy) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return;
        }
        int addCount = totalUseEnergy - userData.getTotalUseEnergy();
        if (addCount <= 0) {
            return;
        }
        userData.setTotalUseEnergy(totalUseEnergy);
        // 更新榜单阵营排行榜单
        CrossXiuXianRank rank = new CrossXiuXianRank(
                String.valueOf(userData.getUserId()), userData.getTotalUseEnergy(), userData.getUpdateEnergyTime());
        synchronized (campEnergyRankMap) {
            campEnergyRankMap.putIfAbsent(userData.getCampId(), new CrossXiuXianRankListModel());
        }
        CrossXiuXianRankListModel rankListModel = campEnergyRankMap.get(userData.getCampId());
        rankListModel.rankChange(rank);

        // 同步更新宗门的总使用次数
        updateCampEnergy(userData.getCampId(), addCount);

        return;
    }

    /**
     * 更新宗门体力共享
     */
    public void updateCampEnergy(int campId, int addCount){
        CrossXiuXianPvpCampData campData = pvpCampDataMap.get(campId);
        if (campData == null || addCount <= 0) {
            return;
        }
        synchronized(campData) {
            campData.setTotalUseEnergy(campData.getTotalUseEnergy() + addCount);
        }
    }

    /**
     * 获取灵峰分配上限
     */
    public int getMountAllotMaxNum(){
        int maxNum = 0;
        for (XiuXianPeakConfig peakConfig:config.getPeakConfigMap().values()) {
            if (peakConfig.getRoomNum() == -1) {
                continue;
            }
            maxNum += peakConfig.getRoomNum() * peakConfig.getPeopleNum();
        }
        return maxNum;
    }

    /**
     * 获取宗门仙力排行榜
     */
    public int getCampPowerRankByCmd(long userId) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        // 上限榜单
        int maxNum = getMountAllotMaxNum();
        int myRank = -1;
        String userIdStr = Long.toString(userId);
        XiuXianProto.XiuXianPowerRankListRespMsg.Builder builder = XiuXianProto.XiuXianPowerRankListRespMsg.newBuilder();
        CrossXiuXianRankListModel model = campUserRankMap.get(userData.getCampId());
        if (model != null) {
            XiuXianProto.XiuXianRankTempMsg.Builder tempRank = XiuXianProto.XiuXianRankTempMsg.newBuilder();
            int num = 0;
            for (CrossXiuXianRank rankData : model.getRankList()) {
                tempRank.setUserId(Long.parseLong(rankData.getId()));
                tempRank.setParam(rankData.getParam());
                tempRank.setValue(Long.toString(rankData.getValue()));
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(tempRank.getUserId());
                if (userBaseInfo == null) {
                    continue;
                }
                PlayerProto.PlayerBaseTempMsg.Builder baseMsg = PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo);
                if(null != baseMsg) {
                    tempRank.setPlayerBaseData(baseMsg);
                }
                builder.addRankList(tempRank);
                num++;
                if (Objects.equals(rankData.getId(), userIdStr)) {
                    myRank = num;
                }
                if (num >= maxNum) {
                    break;
                }
            }
        }
        builder.setRet(0);
        builder.setMyRank(myRank);
        builder.setValue(Integer.toString(userData.getPveProperty().getStateId()));
        builder.setParam(Long.toString(userData.getPveProperty().getPowerVal()));
        sendPacket(ClientProtocol.U_XIU_XIAN_POWER_RANK_LIST, builder, userId);
        return 0;
    }

    /**
     * 检查是否在房间中
     */
    public void checkRoomInPlayers(long userId, int sectId, int mountId, int roomId) {
        synchronized (inRoomPlayers) {
            // 先出房间
            List<Integer> tempUserRoomInfo = userInRoomMap.get(userId);
            if (tempUserRoomInfo != null) {
                if (tempUserRoomInfo.get(1) != mountId || tempUserRoomInfo.get(2) != roomId) {
                    checkRoomOutPlayers(userId, tempUserRoomInfo.get(0), tempUserRoomInfo.get(1), tempUserRoomInfo.get(2));
                }
            }
            // 更新房间
            List<Integer> newUserRoomInfo = new ArrayList<>();
            newUserRoomInfo.add(sectId);
            newUserRoomInfo.add(mountId);
            newUserRoomInfo.add(roomId);
            userInRoomMap.put(userId, newUserRoomInfo);
            // 过滤默认的灵峰
            if (config.getDefaultMount() == mountId) {
                return;
            }
            if (!inRoomPlayers.containsKey(sectId)) {
                inRoomPlayers.put(sectId, new ConcurrentHashMap<>());
            }
            if (!inRoomPlayers.get(sectId).containsKey(mountId)) {
                inRoomPlayers.get(sectId).put(mountId, new ConcurrentHashMap<>());
            }
            if (!inRoomPlayers.get(sectId).get(mountId).containsKey(roomId)) {
                inRoomPlayers.get(sectId).get(mountId).put(roomId, new HashSet<>());
            }
            inRoomPlayers.get(sectId).get(mountId).get(roomId).add(userId);
        }
    }
    /**
     * 离开灵峰房间
     */
    public void checkRoomOutPlayers(long userId, int sectId, int mountId, int roomId) {
        synchronized (inRoomPlayers) {
            if (inRoomPlayers.containsKey(sectId) && inRoomPlayers.get(sectId).containsKey(mountId)
                    && inRoomPlayers.get(sectId).get(mountId).containsKey(roomId)
                    && inRoomPlayers.get(sectId).get(mountId).get(roomId).contains(userId)) {
                inRoomPlayers.get(sectId).get(mountId).get(roomId).remove(userId);
            }
            if (userInRoomMap.containsKey(userId)) {
                userInRoomMap.remove(userId);
            }
        }
    }

    /**
     * 离开灵峰房间
     */
    public void checkRoomOutPlayers(long userId) {
        // 先出房间
        List<Integer> tempUserRoomInfo = userInRoomMap.get(userId);
        if (tempUserRoomInfo != null) {
            checkRoomOutPlayers(userId, tempUserRoomInfo.get(0), tempUserRoomInfo.get(1), tempUserRoomInfo.get(2));
        }
    }

    /**
     * 插入灵峰房间数据
     */
    public void insertCampMountRoom( Map<Integer, Map<Integer, Map<Integer, List<Long>>>> campMountRoomMap, int sectId, int mountId, int roomId, long userId) {
        // 默认灵峰不进入房间
        if (mountId == config.getDefaultMount()) {
            return;
        }
        if (!campMountRoomMap.containsKey(sectId)) {
            campMountRoomMap.put(sectId, new ConcurrentHashMap<>());
        }
        if (!campMountRoomMap.get(sectId).containsKey(mountId)) {
            campMountRoomMap.get(sectId).put(mountId, new ConcurrentHashMap<>());
        }
        if (!campMountRoomMap.get(sectId).get(mountId).containsKey(roomId)) {
            campMountRoomMap.get(sectId).get(mountId).put(roomId, new ArrayList<>());
        }
        campMountRoomMap.get(sectId).get(mountId).get(roomId).add(userId);
    }

    private XiuXianProto.XiuXianAttackedTemp.Builder parseXiuXianAttackedTemp(CrossXiuXianPvpAttackHelper attackHelper) {
        XiuXianProto.XiuXianAttackedTemp.Builder builder = XiuXianProto.XiuXianAttackedTemp.newBuilder();
        builder.setAttackUserId(attackHelper.getAttackUserId());
        builder.setAttackedUserId(attackHelper.getAttackedUserId());
        builder.setHp(attackHelper.getHp());
        builder.setSuckHp(attackHelper.getSuckHp());
        builder.setIsCrit(attackHelper.isCrit());
        builder.setIsDodge(attackHelper.isDodge());
        builder.setAttackHp(attackHelper.getAttackHp());
        builder.setAttackedHp(attackHelper.getAttackedHp());
        return builder;
    }

    /**
     * 被打同步
     */
    private void syncAttackedUser(CrossXiuXianPvpUserData attackUserData, CrossXiuXianPvpUserData attackedUserData, CrossXiuXianPvpAttackHelper attackHelper) {
        XiuXianProto.XiuXianAttackedUserSyncMsg.Builder builder = XiuXianProto.XiuXianAttackedUserSyncMsg.newBuilder();
        if (attackedUserData.getPvpProperty().getHp() <= 0) {
            // 送回出生点
            // 复活时间
            List<Integer> paramList = StringUtils.stringToIntegerList(config.getXIUXIAN_PVP_RESURRECTION_CD(), "\\|");
            int initCd = paramList.get(0);
            int addCd = paramList.get(1);
            int maxCd = paramList.get(2);
            int cd = Math.min(maxCd, initCd + attackedUserData.getReviveCnt() * addCd);
            long nowTime = System.currentTimeMillis();
            attackedUserData.setReviveTime(nowTime + DateHelper.SECOND_MILLIONS * cd);
            // 记录一下被打时间
            attackedUserData.setAttackedTime(nowTime);
            if (isNpc(attackedUserData.getUserId())) {
                // 离开原来的房间
                leavePlace(attackedUserData, 2);
                joinPlace(attackedUserData.getCampId(), attackedUserData);
                // npc不需要往下处理了
                return;
            }
            // 本条命战绩
            builder.setBattleScore(parseXiuXianPvpBattleScoreTemp(attackedUserData.getBattleRecord()));
            // 本轮战绩
            builder.setTotalBattleScore(parseXiuXianPvpBattleScoreTemp(attackedUserData.getBattleRecordMap().get(getCurRound())));
            // 记录一下日志
            CrossAutoLogMgr.add(new LogXiuXianPvpBattle(
                    config.getActivityInfo().getActivityId(),
                    attackedUserData.getCampId(),
                    getCurRound(),
                    attackedUserData.getUserId(),
                    attackedUserData.getPvpProperty().getStateId(),
                    attackedUserData.getPvpProperty().getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.Atk.getValue(), 0L),
                    attackedUserData.getPvpProperty().getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.Hp.getValue(), 0L),
                    attackUserData.getUserId(),
                    attackUserData.getPvpProperty().getStateId(),
                    attackedUserData.getBattleRecord().getKillScore(),
                    new Date(),
                    attackedUserData.getBattleRecord().getSeizePlace(),
                    attackedUserData.getBattleRecord().getSeizeScore()
            ));
        }
        // 通知被打的人
        builder.setAttackUserData(parseXiuXianPvpOtherUserTemp(attackUserData));
        builder.setAttack(parseXiuXianAttackedTemp(attackHelper));
        builder.setPvpUserData(parseXiuXianPvpUserDataTemp(attackedUserData));
        sendPacket(ClientProtocol.U_XIU_XIAN_ATTACKED_USER_SYNC, builder, attackedUserData.getUserId());
    }

    /**
     * 某轮战绩
     *
     */
    private XiuXianProto.XiuXianPvpBattleScoreTemp.Builder parseXiuXianPvpBattleScoreTemp(CrossXiuXianPvpBattleRecord battleRecord) {
        // 统计战报
        XiuXianProto.XiuXianPvpBattleScoreTemp.Builder builder = XiuXianProto.XiuXianPvpBattleScoreTemp.newBuilder();
        int kill = 0;
        long killScore = 0;
        int seize = 0;
        long seizeScore = 0;
        if (battleRecord != null) {
            kill = battleRecord.getKill();
            killScore = battleRecord.getKillScore();
            seize = battleRecord.getSeize();
            seizeScore = battleRecord.getSeizeScore();
        }
        builder.setKill(kill);
        builder.setKillScore(killScore);
        builder.setSeize(seize);
        builder.setSeizeScore(seizeScore);
        return builder;
    }


    /**
     * 复活逻辑
     */
    public void revive(CrossXiuXianPvpUserData userData) {
        // 开始复活
        userData.setReviveCnt(userData.getReviveCnt() + 1);
        // 属性更新
        updatePvpProperty(userData);
        // 清空本条命战绩
        userData.setBattleRecord(new CrossXiuXianPvpBattleRecord());
    }

    /**
     * 更新pvp属性
     */
    public void updatePvpProperty(CrossXiuXianPvpUserData userData) {
        XiuXianPvpUserProperty pvpProperty = new XiuXianPvpUserProperty();
        // 获取pve属性
        XiuXianPveUserProperty pveProperty = userData.getPveProperty();
        // 设置下最新属性
        pvpProperty.setAttrMap(new HashMap<>(pveProperty.getAttrMap()));
        // 设置下当前血量
        pvpProperty.setHp(pveProperty.getAttrMap().getOrDefault(eXiuXianType.BattleAttrType.Hp.getValue(),0L));
        // 战力
        pvpProperty.setAbility(pveProperty.getPowerVal());
        pvpProperty.setStateId(pveProperty.getStateId());
        // 搞个特效
        int effectId = 1;
        XiuXianStateConfig xiuXianStateConfig = config.getStateConfigMap().get(pvpProperty.getStateId());
        if (xiuXianStateConfig != null) {
            if (xiuXianStateConfig.getMaxEffect() <= 3) {
                effectId = randomHelper.next(1, 3);
            } else {
                effectId = xiuXianStateConfig.getMaxEffect();
            }
        }
        pvpProperty.setEffectId(effectId);
        userData.setPvpProperty(pvpProperty);
    }


    /**
     * 移动逻辑
     *
     * @param pvpUserData 用户数据
     * @param position    位置信息
     */
    private void move(CrossXiuXianPvpUserData pvpUserData, CrossXiuXianPvpPosition position) {
        pvpUserData.setPosition(position);
        pvpUserData.setLastPingPlaceTime(position.getTime());
    }
    /**
     * 初始化灵峰分配-启动服务器
     */
    private void initMountAllotDetail(CrossXiuXianPvpUserData userData) {
        for (XiuXianRoomMemberInfo roomMemberInfo : userData.getMountData().getAllAllotMap().values()) {
            if (!allotMap.containsKey(roomMemberInfo.getId())) {
                allotMap.put(roomMemberInfo.getId(), new ConcurrentHashMap<>());
            }
            allotMap.get(roomMemberInfo.getId()).put(userData.getUserId(), roomMemberInfo);
        }
    }

    /**
     * 初始化全部榜单
     */
    private void initAllRankList() {
        Map<Integer, CrossXiuXianRankListModel> campUserMap = new ConcurrentHashMap<>();
        Map<Integer, CrossXiuXianRankListModel> campEnergyMap = new ConcurrentHashMap<>();
        Map<Integer, Map<Integer, Map<Integer, List<Long>>>> tempCampMountRoomMap = new ConcurrentHashMap<>();

        CrossXiuXianRankListModel userScoreRankModel = new CrossXiuXianRankListModel();
        for (CrossXiuXianPvpUserData userData : pvpUserDataMap.values()) {
            if (!(userData.getPveProperty().getStateId() <= config.getInitStateId() && userData.getPveProperty().getPowerVal() <= 0L)) {
                // 宗门仙力排行榜
                CrossXiuXianRank rank = new CrossXiuXianRank(String.valueOf(userData.getUserId()), userData.getPveProperty().getStateId(), userData.getUpdatePropertyTime(), String.valueOf(userData.getPveProperty().getPowerVal()));
                campUserMap.putIfAbsent(userData.getCampId(), new CrossXiuXianRankListModel());
                campUserMap.get(userData.getCampId()).rankChange(rank);
                // 个人战绩排行
                long totalScore = calcTotalScore(userData);
                if (totalScore > 0) {
                    userScoreRankModel.rankChange(new CrossXiuXianRank(String.valueOf(userData.getUserId()), totalScore, userData.getUpdateScoreTime()));
                }
            }
            if (userData.getTotalUseEnergy() > 0) {
                CrossXiuXianRank rank = new CrossXiuXianRank(String.valueOf(userData.getUserId()), userData.getTotalUseEnergy(), userData.getUpdateEnergyTime());
                campEnergyMap.putIfAbsent(userData.getCampId(), new CrossXiuXianRankListModel());
                campEnergyMap.get(userData.getCampId()).rankChange(rank);
            }
            // 初始化数据
            if (userData.getMountData().getNewId() > 0) {
                XiuXianRoomMemberInfo curMountInfo = getDetailRoomInfo(userData, userData.getMountData().getNewId());
                insertCampMountRoom(tempCampMountRoomMap, userData.getCampId(), curMountInfo.getMountId(), curMountInfo.getRoomId(), userData.getUserId());
            }
            // 初始化
            initMountAllotDetail(userData);
        }
        CrossXiuXianRankListModel campScoreRankModel = new CrossXiuXianRankListModel();
        CrossXiuXianRankListModel campTotalScoreRankModel = new CrossXiuXianRankListModel();
        for (CrossXiuXianPvpCampData campData : pvpCampDataMap.values()) {
            // 当前轮次
            campScoreRankModel.rankChange(new CrossXiuXianRank(String.valueOf(campData.getCampId()), campData.getScore(), campData.getUpdateScoreTime()));
            // 活动总积分
            campTotalScoreRankModel.rankChange(new CrossXiuXianRank(String.valueOf(campData.getCampId()), campData.getTotalScore(), campData.getUpdateScoreTime()));
        }
        campUserRankMap = campUserMap;
        campEnergyRankMap = campEnergyMap;
        campScoreRankMap = campScoreRankModel;
        campTotalScoreRankMap = campTotalScoreRankModel;
        userScoreRank = userScoreRankModel;
        campMountRoomMap = tempCampMountRoomMap;
    }

    /**
     * 同步宗门信息到本宗门的成员
     */
    public void syncCampInfoToAllCampMember(int campId) {
        CrossXiuXianPvpCampData campData = getPvpCampData(campId);
        if (campData == null) {
            return;
        }
        XiuXianProto.XiuXianCampSyncMsg.Builder builder = XiuXianProto.XiuXianCampSyncMsg.newBuilder();
        builder.setCamp(parseXiuXianCampTemp(campData));
        Set<Long> list = getUserIdListInActivityByCampId(campId);
        sendPacketToAll(Protocol.U_XIU_XIAN_CAMP_SYNC, builder, list);
    }

    public Set<Long> getUserIdListInActivityByCampId(int campId) {
        Set<Long> list = new HashSet<>();
        for (CrossXiuXianPvpUserData userData : pvpUserDataMap.values()) {
            if (!isAble(userData.getUserId())) {
                continue;
            }
            // 没资格不推
            if (!isAble(userData.getUserId())) {
                continue;
            }
            // 只同步本阵营的玩家
            if (userData.getCampId() != campId) {
                continue;
            }
            list.add(userData.getUserId());
        }
        return list;
    }

    public XiuXianProto.XiuXianPvpUserDataTemp.Builder parseXiuXianPvpUserDataTemp(CrossXiuXianPvpUserData pvpUserData) {
        if (pvpUserData == null) {
            return null;
        }
        XiuXianProto.XiuXianPvpUserDataTemp.Builder builder = XiuXianProto.XiuXianPvpUserDataTemp.newBuilder();
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setProperty(parseXiuXianUserPvpPropertyTemp(pvpUserData));
        builder.setCampId(pvpUserData.getCampId());
        builder.setPlaceId(pvpUserData.getPlaceId());
        builder.setTransferTime(pvpUserData.getTransferTime());
        builder.setAttackTime(pvpUserData.getAttackTime());
        builder.setAttackedTime(pvpUserData.getAttackedTime());
        builder.setReviveTime(pvpUserData.getReviveTime());
        return builder;
    }

    public XiuXianProto.XiuXianPvpUserPropertyTemp.Builder parseXiuXianUserPvpPropertyTemp(CrossXiuXianPvpUserData userData) {
        if (userData == null) {
            return null;
        }
        Map<Integer, Long> attrMap = userData.getPvpProperty().getAttrMap();
        XiuXianProto.XiuXianPvpUserPropertyTemp.Builder builder = XiuXianProto.XiuXianPvpUserPropertyTemp.newBuilder();
        builder.setAttack(attrMap.getOrDefault(eXiuXianType.BattleAttrType.Atk.getValue(), 0L));
        builder.setTotalHp(attrMap.getOrDefault(eXiuXianType.BattleAttrType.Hp.getValue(), 0L));
        builder.setAttackSpeed(Math.toIntExact(attrMap.getOrDefault(eXiuXianType.BattleAttrType.AtkSpeed.getValue(), 0L)));
        builder.setHp(userData.getPvpProperty().getHp());
        builder.setAbility(userData.getPvpProperty().getAbility());
        builder.setStateId(userData.getPvpProperty().getStateId());
        builder.setEffectId(userData.getPvpProperty().getEffectId());
        return builder;
    }

    public XiuXianProto.XiuXianPvpUserPropertyTemp.Builder parseXiuXianUserPvePropertyTemp(CrossXiuXianPvpUserData userData) {
        if (userData == null) {
            return null;
        }
        XiuXianProto.XiuXianPvpUserPropertyTemp.Builder builder = XiuXianProto.XiuXianPvpUserPropertyTemp.newBuilder();
        Map<Integer, Long> attrMap = userData.getPveProperty().getAttrMap();
        builder.setAttack(attrMap.getOrDefault(eXiuXianType.BattleAttrType.Atk.getValue(), 0L));
        builder.setTotalHp(attrMap.getOrDefault(eXiuXianType.BattleAttrType.Hp.getValue(), 0L));
        builder.setHp(attrMap.getOrDefault(eXiuXianType.BattleAttrType.Hp.getValue(), 0L));
        builder.setAttackSpeed(Math.toIntExact(attrMap.getOrDefault(eXiuXianType.BattleAttrType.Atk.getValue(), 0L)));
        builder.setAbility(userData.getPveProperty().getPowerVal());
        builder.setStateId(userData.getPveProperty().getStateId());
        builder.setEffectId(userData.getPvpProperty().getEffectId());
        return builder;
    }

    public XiuXianPveUserProperty parseXiuXianUserPveProperty(XiuXianProto.XiuXianPvePropertyForCrossTemp temp) {
        XiuXianPveUserProperty property = new XiuXianPveUserProperty();
        property.setPowerVal(temp.getPowerVal());
        property.setStateId(temp.getStateId());
        property.setPracticeSpeed(temp.getPracticeSpeed());
        property.setImageId(temp.getImageId());
        // 属性
        for (XiuXianProto.XiuXianAttrInfoTemp attrTemp : temp.getAttrListList()) {
            int attrId = attrTemp.getAttrId();
            long value = attrTemp.getAttrValue();
            property.getAttrMap().put(attrId, value);
        }
        return property;
    }

    public XiuXianProto.XiuXianPvpPositionTemp.Builder parseXiuXianPvpPositionTemp(CrossXiuXianPvpPosition position) {
        if (position == null) {
            return null;
        }
        XiuXianProto.XiuXianPvpPositionTemp.Builder builder = XiuXianProto.XiuXianPvpPositionTemp.newBuilder();
        builder.setX(position.getX());
        builder.setY(position.getY());
        builder.setDirX(position.getDirX());
        builder.setDirY(position.getDirY());
        builder.setTime(position.getTime());
        return builder;
    }

    public XiuXianProto.XiuXianCampTemp.Builder parseXiuXianCampTemp(CrossXiuXianPvpCampData campData) {
        if (campData == null) {
            return null;
        }
        XiuXianProto.XiuXianCampTemp.Builder builder = XiuXianProto.XiuXianCampTemp.newBuilder();
        builder.setCampId(campData.getCampId());
        // 宗主信息
        if (campData.getMajorUserId() != 0) {
            CrossXiuXianPvpUserData majorUser = getPvpUserData(campData.getMajorUserId());
            if (majorUser != null) {
                builder.setMajorUser(parseXiuXianPvpUserDetailTemp(majorUser));
            }
        }
        // 副宗主信息
        if (campData.getMinorUserId() != 0) {
            CrossXiuXianPvpUserData minorUser = getPvpUserData(campData.getMinorUserId());
            if (minorUser != null) {
                builder.setMinorUser(parseXiuXianPvpUserDetailTemp(minorUser));
            }
        }
        builder.setMajorPlaceId(campData.getMajorPlaceId());
        builder.setMinorPlaceId(campData.getMinorPlaceId());
        builder.setAppointTime(campData.getAppointTime());
        builder.setMajorMarkTime(campData.getMajorMarkTime());
        builder.setMinorMarkTime(campData.getMinorMarkTime());
        return builder;
    }

    public XiuXianProto.XiuXianPvpPlaceInfoTemp.Builder parseXiuXianPvpPlaceInfoTemp(CrossXiuXianPvpPlaceData placeData) {
        if (placeData == null) {
            return null;
        }
        XiuXianProto.XiuXianPvpPlaceInfoTemp.Builder builder = XiuXianProto.XiuXianPvpPlaceInfoTemp.newBuilder();
        builder.setPlaceId(placeData.getPlaceId());
        // 组装房间玩家信息
        for (Long userId : placeData.getUserList()) {
            CrossXiuXianPvpUserData pvpUserData = getPvpUserData(userId);
            if (pvpUserData == null) {
                continue;
            }
            if (!isBirthPlace(placeData.getPlaceId()) && pvpUserData.getUserState() == 1) {
                continue;
            }
            builder.addUser(parseXiuXianPvpOtherUserTemp(pvpUserData));
        }
        builder.setCampId(placeData.getCampId());
        builder.setSeizeTime(placeData.getSeizeTime());
        return builder;
    }

    public XiuXianProto.XiuXianPvpPlayerSimpleTempMsg.Builder parseXiuXianPvpPlayerSimpleTempMsg(long userId) {
        XiuXianProto.XiuXianPvpPlayerSimpleTempMsg.Builder builder = XiuXianProto.XiuXianPvpPlayerSimpleTempMsg.newBuilder();
        if (isNpc(userId)) {
            CrossXiuXianNpcDataHelper dataHelper = npcDataMap.get(userId);
            builder.setDecoration(dataHelper.getDecoration());
            builder.setNickName(dataHelper.getNickName());
            builder.setUserId(userId);
            builder.setServerId(config.getActivityInfo().getServerIdList().get(randomHelper.next(0, config.getActivityInfo().getServerIdList().size())));
        } else {
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
            if (userBaseInfo != null) {
                builder.setDecoration(userBaseInfo.getDecoration());
                builder.setNickName(userBaseInfo.getNickName());
                builder.setServerId(userBaseInfo.getServerId());
                builder.setUserId(userId);
            }
        }
        return builder;
    }

    public XiuXianProto.XiuXianPvpOtherUserTemp.Builder parseXiuXianPvpOtherUserTemp(CrossXiuXianPvpUserData pvpUserData) {
        if (pvpUserData == null) {
            return null;
        }
        XiuXianProto.XiuXianPvpOtherUserTemp.Builder builder = XiuXianProto.XiuXianPvpOtherUserTemp.newBuilder();
        builder.setCampId(pvpUserData.getCampId());
        builder.setPlayerData(parseXiuXianPvpPlayerSimpleTempMsg(pvpUserData.getUserId()));
        builder.setProperty(parseXiuXianUserPvpPropertyTemp(pvpUserData));
        builder.setPlaceId(pvpUserData.getPlaceId());
        builder.setPosition(parseXiuXianPvpPositionTemp(pvpUserData.getPosition()));
        builder.setReviveTime(pvpUserData.getReviveTime());
        return builder;
    }

    public XiuXianProto.XiuXianPvpPlaceSeizeInfoTemp.Builder parseXiuXianPvpPlaceSeizeInfoTemp(CrossXiuXianPvpPlaceSeizeInfo seizeData, Map<Integer, Integer> campCnt) {
        if (seizeData == null) {
            return null;
        }
        XiuXianProto.XiuXianPvpPlaceSeizeInfoTemp.Builder builder = XiuXianProto.XiuXianPvpPlaceSeizeInfoTemp.newBuilder();
        builder.setCampId(seizeData.getCampId());
        builder.setSeizeTime(seizeData.getSeizeTime());
        // 宗门人数
        builder.setNum(campCnt.getOrDefault(seizeData.getCampId(), 0));
        return builder;
    }

    public CrossXiuXianPvpPosition parseCrossXiuXianPvpPosition(XiuXianProto.XiuXianPvpPositionTemp temp) {
        CrossXiuXianPvpPosition position = new CrossXiuXianPvpPosition();
        position.setX(temp.getX());
        position.setY(temp.getY());
        position.setDirX(temp.getDirX());
        position.setDirY(temp.getDirY());
        position.setTime(temp.getTime());
        return position;
    }

    public XiuXianProto.XiuXianPvpUserDetailTemp.Builder parseXiuXianPvpUserDetailTemp(CrossXiuXianPvpUserData pvpUserData) {
        if (pvpUserData == null) {
            return null;
        }
        XiuXianProto.XiuXianPvpUserDetailTemp.Builder builder = XiuXianProto.XiuXianPvpUserDetailTemp.newBuilder();
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(pvpUserData.getUserId());
        if (userBaseInfo == null) {
            return null;
        }
        builder.setUserId(pvpUserData.getUserId());
        builder.setUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        builder.setProperty(parseXiuXianUserPvpPropertyTemp(pvpUserData));
        return builder;
    }

    public XiuXianProto.XiuXianPvpUserDetailTemp.Builder parseXiuXianPveUserDetailTemp(CrossXiuXianPvpUserData userData) {
        if (userData == null) {
            return null;
        }
        XiuXianProto.XiuXianPvpUserDetailTemp.Builder builder = XiuXianProto.XiuXianPvpUserDetailTemp.newBuilder();
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userData.getUserId());
        if (userBaseInfo == null) {
            return null;
        }
        builder.setUserId(userData.getUserId());
        builder.setUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        builder.setProperty(parseXiuXianUserPvePropertyTemp(userData));
        return builder;
    }

    public CrossXiuXianPvpData getCrossXiuXianPvpData() {
        return crossXiuXianPvpData;
    }

    public boolean isCampNotice(CrossXiuXianPvpNoticeData noticeData) {
        if (noticeData == null) {
            return false;
        }
        return eXiuXianPvpNoticeType.Appoint.getValue() == noticeData.getNoticeType()
                || eXiuXianPvpNoticeType.CancelAppoint.getValue() == noticeData.getNoticeType()
                || eXiuXianPvpNoticeType.MajorMarkPlace.getValue() == noticeData.getNoticeType()
                || eXiuXianPvpNoticeType.MinorMarkPlace.getValue() == noticeData.getNoticeType()
                || eXiuXianPvpNoticeType.LosePlace.getValue() == noticeData.getNoticeType();
    }

    /**
     * 增加公告
     *
     * @param noticeData 公告信息
     * @param userId1 操作者id
     * @param userId2 被操作者id
     */
    public void addPvpNoticeData(CrossXiuXianPvpNoticeData noticeData, long userId1, long userId2) {
        // 添加操作者信息
        if (userId1 != 0) {
            CrossXiuXianPvpUserData userData = getPvpUserData(userId1);
            if (userData != null) {
                CrossXiuXianPvpNoticeUserData noticeUserData = new CrossXiuXianPvpNoticeUserData();
                noticeUserData.setUserId(userData.getUserId());
                if (isNpc(userId1)) {
                    CrossXiuXianNpcDataHelper dataHelper = npcDataMap.get(userId1);
                    if (dataHelper != null) {
                        noticeUserData.setNickName(dataHelper.getNickName());
                        noticeUserData.setServerId(dataHelper.getServerId());
                        noticeUserData.setDecoration(dataHelper.getDecoration());
                    }
                } else {
                    CrossUserBaseInfo userBaseInfo = CrossUserMgr.getCrossUserBaseInfo(userId1);
                    if (userBaseInfo != null && userBaseInfo.getUserBaseInfo() != null) {
                        noticeUserData.setNickName(userBaseInfo.getUserBaseInfo().getNickName());
                        noticeUserData.setServerId(userBaseInfo.getUserBaseInfo().getServerId());
                        noticeUserData.setDecoration(userBaseInfo.getUserBaseInfo().getDecoration());
                    }
                }
                noticeUserData.setStateId(userData.getPveProperty().getStateId());
                noticeData.setUser1(noticeUserData);
            }
        }
        // 添加被操作者信息
        if (userId2 != 0) {
            CrossXiuXianPvpUserData userData = getPvpUserData(userId2);
            if (userData != null) {
                CrossXiuXianPvpNoticeUserData noticeUserData = new CrossXiuXianPvpNoticeUserData();
                noticeUserData.setUserId(userData.getUserId());
                if (isNpc(userId2)) {
                    CrossXiuXianNpcDataHelper dataHelper = npcDataMap.get(userId2);
                    if (dataHelper != null) {
                        noticeUserData.setNickName(dataHelper.getNickName());
                        noticeUserData.setServerId(dataHelper.getServerId());
                        noticeUserData.setDecoration(dataHelper.getDecoration());
                    }
                } else {
                    CrossUserBaseInfo userBaseInfo = CrossUserMgr.getCrossUserBaseInfo(userId2);
                    if (userBaseInfo != null && userBaseInfo.getUserBaseInfo() != null) {
                        noticeUserData.setNickName(userBaseInfo.getUserBaseInfo().getNickName());
                        noticeUserData.setServerId(userBaseInfo.getUserBaseInfo().getServerId());
                        noticeUserData.setDecoration(userBaseInfo.getUserBaseInfo().getDecoration());
                    }
                }
                noticeUserData.setStateId(userData.getPveProperty().getStateId());
                noticeData.setUser2(noticeUserData);
            }
        }
        noticeData.setInsertOption();
        XiuXianProto.XiuXianNoticeSyncMsg.Builder syncMsg = XiuXianProto.XiuXianNoticeSyncMsg.newBuilder();
        if (isCampNotice(noticeData)) {
            // 宗门公告
            int campId = noticeData.getCampId();
            if (campId == 0) {
                return;
            }
            // 添加宗门公告
            synchronized (campNoticeDataMap) {
                LinkedList<CrossXiuXianPvpNoticeData> list = campNoticeDataMap.get(campId);
                while (list.size() > config.getXIUXIAN_PVP_NOTICE_NUM()) {
                    list.removeFirst();
                }
                list.addLast(noticeData);
                campNoticeDataMap.put(campId, list);
            }
            XiuXianProto.XiuXianNoticeTemp.Builder noticeTemp = parseXiuXianNoticeTemp(noticeData);
            if (noticeTemp != null) {
                syncMsg.setCampNotice(noticeTemp);
                // 推送公告给宗门在线成员
                Set<Long> list = getUserIdListInActivityByCampId(campId);
                sendPacketToAll(Protocol.U_XIU_XIAN_NOTICE_SYNC, syncMsg, list);
            }
        } else {
            // 全服公告
            synchronized (noticeDataList) {
                while (noticeDataList.size() > config.getXIUXIAN_PVP_NOTICE_NUM()) {
                    noticeDataList.removeFirst();
                }
                noticeDataList.add(noticeData);
            }
            XiuXianProto.XiuXianNoticeTemp.Builder noticeTemp = parseXiuXianNoticeTemp(noticeData);
            if (noticeTemp != null) {
                syncMsg.setNotice(noticeTemp);
                // 推送公告给在线用户
                sendPacketToAll(Protocol.U_XIU_XIAN_NOTICE_SYNC, syncMsg, new ArrayList<>(inPvpActivity));
            }
        }
    }
    /**
     * 同步宗门体力-区服定时拿获取
     */
    public void syncCampEnergyByCmd(long serverId) {
        // 宗门id
        int campId = getCampIdByServerId(serverId);
        if (campId == 0) {
            return;
        }
        CrossXiuXianPvpCampData campData = getPvpCampData(campId);
        if (campData == null) {
            return;
        }
        XiuXianProto.CrossXiuXianSyncCampEnergyRespMsg.Builder builder = XiuXianProto.CrossXiuXianSyncCampEnergyRespMsg.newBuilder();
        builder.setCampTotalEnergy(campData.getTotalUseEnergy());
        YanQuMessage message = YanQuMessageUtils.buildMessage(GameProtocol.S_XIU_XIAN_SYNC_SECT_ENERGY_FROM_CROSS, builder);
        MessageHelper.sendPacket(serverId, 0, message);
    }
    /**
     * 区服确认同步灵峰分配
     */
    public void ackMountAllotByCmd(long serverId, long allotId) {
        synchronized (mountAllotDataMap) {
            CrossXiuXianMountAllotData mountAllotData = mountAllotDataMap.get(allotId);
            if (mountAllotData == null) {
                return;
            }
            List<Long> atkServerList = mountAllotData.getAckServerIdList();
            if (atkServerList.contains(serverId)) {
                return;
            }
            atkServerList.add(serverId);
            mountAllotData.setAckServerIdList(atkServerList);
        }
    }


    public void sendChatByCmd(long userId, CrossActivityProto.CrossActivityChatReqMsg.Builder reqMsg) {
        int range = 0;
        int id = 0;
        if (eMessageType.XiuXianPublicChat.getValue() == reqMsg.getMsg().getType()) {
            range = CrossXiuXianChatLogic.RANGE_ALL;
            id = config.getActivityInfo().getActivityId();
            // 公屏聊天加上阵营
            WorldMessageProto.WorldMessageTempMsg.Builder message = reqMsg.getMsg().toBuilder();
            message.setExtraParams(String.valueOf(getCampByUserId(userId)));
            reqMsg.setMsg(message);
        } else if (eMessageType.XiuXianCampChat.getValue() == reqMsg.getMsg().getType()) {
            range = CrossXiuXianChatLogic.RANGE_CAMP;
            id = getCampByUserId(userId);
        }

        if (range <= 0 || id <= 0) {
            return;
        }

        chatLogic.chat(range, id, 1, reqMsg.getMsg());
    }

    /**
     * 区服评分上报
     */
    public void getServerScore(long serverId, long serverScore) {
        // 上报数据
        // 先判断下区服有没有上报了
        List<Long> list = new ArrayList<>();
        synchronized (lock) {
            for (CrossXiuXianServerScoreData serverScoreData : serverScoreDataList) {
                list.addAll(serverScoreData.getServerIdList());
            }
            if (list.contains(serverId)) {
                // 已上报的跳过处理
                return;
            }
            if (!config.getActivityInfo().getServerIdList().contains(serverId)) {
                return;
            }
            // 获取下商会跨服分组
//            CrossUnionServerGroup group = CrossUnionServerGroupMgr.getServerGroupByServerId(serverId);
            // 看下有没有分组数据
//            boolean isFind = false;
//            CrossXiuXianServerScoreData serverScoreData = null;
//            for (CrossXiuXianServerScoreData scoreData : serverScoreDataList) {
//                if (isFind) {
//                    break;
//                }
//                if (group != null && group.getState() == 1) {
//                    for (Long id : scoreData.getServerIdList()) {
//                        if (group.getServerList().contains(id)) {
//                            serverScoreData = scoreData;
//                            isFind = true;
//                            break;
//                        }
//                    }
//                }
//            }
//            if (isFind) {
//                // 塞到分组里
//                Set<Long> serverIdList = serverScoreData.getServerIdList();
//                if (serverIdList.add(serverId)) {
//                    serverScoreData.setServerIdList(serverIdList);
//                    serverScoreData.setServerScore(serverScoreData.getServerScore() + serverScore);
//                }
//            } else {
            // 新加个分组
            CrossXiuXianServerScoreData newServerScoreData = new CrossXiuXianServerScoreData();
            Set<Long> serverIdList = new HashSet<>();
            serverIdList.add(serverId);
            newServerScoreData.setUuid(UUID.randomUUID().toString());
            newServerScoreData.setActivityId(config.getActivityInfo().getActivityId());
            newServerScoreData.setServerIdList(serverIdList);
            newServerScoreData.setServerScore(serverScore);
            newServerScoreData.setInsertOption();
            serverScoreDataList.add(newServerScoreData);
//            }
        }
        // 判断下是否收集完毕
        List<Long> serverList = getNeedGetScoreServerList();
        if (serverList.size() == 0) {
            // 收集完毕后分配一下宗门
            crossXiuXianGenCampTask();
        }
    }

    public void getChatByCmd(long userId, List<Integer> paramList) {
        if (paramList.isEmpty()) {
            return;
        }
        List<WorldMessageProto.WorldMessageTempMsg> dataList = new ArrayList<>();
        for (int range : paramList) {
            int id = 0;
            if (range == CrossXiuXianChatLogic.RANGE_ALL) {
                id = config.getActivityInfo().getActivityId();
            } else if (range == CrossXiuXianChatLogic.RANGE_CAMP) {
                id = getCampByUserId(userId);
            }

            if (range <= 0 || id <= 0) {
                continue;
            }
            dataList.addAll(chatLogic.getChatMsg(range, id));
        }
        CrossActivityProto.CrossActivityChatListRespMsg.Builder respMsg = CrossActivityProto.CrossActivityChatListRespMsg.newBuilder();
        respMsg.setActivityId(config.getActivityInfo().getActivityId());

        if (dataList.size() > 0) {
            dataList.sort(Comparator.comparingLong(WorldMessageProto.WorldMessageTempMsg::getSendTime));
            WorldMessageProto.WorldMessageListMsg.Builder worldMessageListMsg = WorldMessageProto.WorldMessageListMsg.newBuilder();
            worldMessageListMsg.addAllDataList(dataList);
            respMsg.setDataList(worldMessageListMsg);
        }
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if (userBaseInfo != null) {
            YanQuMessage pbMsg = YanQuMessageUtils.buildMessage(Protocol.U_CROSS_ACTIVITY_CHAT_LIST, respMsg);
            MessageHelper.sendPacket(userBaseInfo.getServerId(), userId, pbMsg);
        }
    }

    public void syncChat(int range, int id, WorldMessageProto.WorldMessageTempMsg chatMsg) {
        List<Long> userIdList = new ArrayList<>();
        if (range == CrossXiuXianChatLogic.RANGE_ALL) {
            // 所有人都要接收，所以换个发包方式
            YanQuMessage pbMsg = YanQuMessageUtils.buildMessage(Protocol.A_WORLD_MESSAGE_TRANSFER, chatMsg);
            for (long serverId : config.getActivityInfo().getServerIdList()) {
                MessageHelper.sendPacket(serverId, 0, pbMsg);
            }
            return;
        } else if (range == CrossXiuXianChatLogic.RANGE_CAMP) {
            userIdList = pvpUserDataMap.values().stream().filter(item -> item.getCampId() == id).mapToLong(CrossXiuXianPvpUserData::getUserId).boxed().collect(Collectors.toList());
        }
        if (!userIdList.isEmpty()) {
            sendPacketToAll(ClientProtocol.U_WORLD_MESSAGE_SYNC, chatMsg.toBuilder(), userIdList);
        }
    }

    public void getRankRewardByCmd(long userId, XiuXianProto.XiuXianGetRankRewardReqMsg reqMsg) {
        int ret = getRankReward(userId, reqMsg.getConditionType());
        if (ret != 0) {
            XiuXianProto.XiuXianGetRankRewardRespMsg.Builder builder = XiuXianProto.XiuXianGetRankRewardRespMsg.newBuilder();
            builder.setRet(ret);
            sendPacket(ClientProtocol.U_XIU_XIAN_GET_RANK_REWARD, builder, userId);
        }
    }

    public void getCampRankListByCmd(long userId) {
        XiuXianProto.XiuXianGetCampRankRespMsg.Builder builder = XiuXianProto.XiuXianGetCampRankRespMsg.newBuilder();
        builder.setRet(0);
        LinkedList<CrossXiuXianRank> rankList = campTotalScoreRankMap.getRankList();
        for (CrossXiuXianRank rank : rankList) {
            builder.addRank(parseXiuXianCampRankMsg(rank));
        }

        sendPacket(ClientProtocol.U_XIU_XIAN_GET_CAMP_RANK_LIST, builder, userId);
    }

    public void getCampScoreRecordByCmd(long userId, int campId) {
        XiuXianProto.XiuXianGetCampScoreRecordRespMsg.Builder builder = XiuXianProto.XiuXianGetCampScoreRecordRespMsg.newBuilder();
        builder.setRet(0);
        for (Map.Entry<Integer, Map<Integer, CrossXiuXianPvpCampScoreRecord>> entry : crossXiuXianPvpData.getCampScoreRecordMap().entrySet()) {
            XiuXianProto.XiuXianCampScoreRecordTemp.Builder temp = XiuXianProto.XiuXianCampScoreRecordTemp.newBuilder();
            int round = entry.getKey();
            long score = 0;
            CrossXiuXianPvpCampScoreRecord record = entry.getValue().get(campId);
            if (record != null) {
                score = record.getScore();
            }
            temp.setRound(round);
            temp.setScore(score);
            builder.addScore(temp);
        }
        sendPacket(ClientProtocol.U_XIU_XIAN_GET_CAMP_SCORE_RECORD, builder, userId);
    }

    public XiuXianProto.XiuXianCampRankMsg.Builder parseXiuXianCampRankMsg(CrossXiuXianRank rank) {
        int campId = Integer.parseInt(rank.getId());
        XiuXianProto.XiuXianCampRankMsg.Builder builder = XiuXianProto.XiuXianCampRankMsg.newBuilder();
        builder.setCampId(campId);
        builder.setValue(rank.getValue());
        return builder;
    }


    public void getUserRankListByCmd(long userId, XiuXianProto.XiuXianGetUserRankReqMsg reqMsg) {
        int type = reqMsg.getType();

        long myValue = calcTotalScore(getPvpUserData(userId));
        String myId = String.valueOf(userId);
        LinkedList<CrossXiuXianRank> rankList;
        int maxRank = 100;

        if (type == 1) {
            // 【个人榜】
            rankList = userScoreRank.getRankList();
            maxRank = userMaxRankConfig;
        } else if (type == 2) {
            // 【阵营内个人榜】
            int campId = Integer.parseInt(reqMsg.getParam());
            CrossXiuXianPvpCampData campData = getPvpCampData(campId);
            if (campData == null) {
                return; // 参数错误
            }
            // 组装个榜单
            CrossXiuXianRankListModel tmpModel = new CrossXiuXianRankListModel();
            LinkedList<CrossXiuXianRank> tmpList = new LinkedList<>();
            for (CrossXiuXianPvpUserData userData : pvpUserDataMap.values()) {
                if (userData.getCampId() != campId) {
                    continue;
                }
                long totalScore = calcTotalScore(userData);
                if (totalScore > 0) {
                    tmpList.add(new CrossXiuXianRank(String.valueOf(userData.getUserId()), totalScore, userData.getUpdateScoreTime()));
                }
            }
            tmpModel.setRankList(tmpList); // 排序
            rankList = tmpModel.getRankList();
        } else {
            return; // 参数错误
        }

        XiuXianProto.XiuXianGetUserRankRespMsg.Builder builder = XiuXianProto.XiuXianGetUserRankRespMsg.newBuilder();
        builder.setRet(0);

        int myRank = -1;
        int rankNum = 0;
        for (CrossXiuXianRank rank : rankList) {
            rankNum++;
            if (rankNum > maxRank) {
                break;
            }
            if (Objects.equals(rank.getId(), myId)) {
                myRank = rankNum;
            }
            builder.addRank(parseXiuXianUserRankMsg(rank));
        }

        builder.setMyRank(myRank);
        builder.setMyValue(myValue);
        sendPacket(ClientProtocol.U_XIU_XIAN_GET_USER_RANK_LIST, builder, userId);
    }

    public XiuXianProto.XiuXianUserRankMsg.Builder parseXiuXianUserRankMsg(CrossXiuXianRank rank) {
        long userId = Long.parseLong(rank.getId());
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if (userBaseInfo == null) {
            userBaseInfo = new UserBaseInfo();
        }
        int campId = getCampByUserId(userId);

        XiuXianProto.XiuXianUserRankMsg.Builder builder = XiuXianProto.XiuXianUserRankMsg.newBuilder();
        builder.setUserId(userId);
        builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        builder.setValue(rank.getValue());
        builder.setCampId(campId);
        return builder;
    }

    /**
     * 领取榜单奖励
     */
    private int getRankReward(long userId, int conditionType) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_XIU_XIAN_PVP_USER_NOT_FOUND;
        }
        // 拿榜单
        String myId;
        LinkedList<CrossXiuXianRank> rankList;
        if (conditionType == eGamePlayerEventType.XiuXianPersonalScoreRank.getValue()) {
            rankList = userScoreRank.getRankList();
            myId = String.valueOf(userId);
        }  else if (conditionType == eGamePlayerEventType.XiuXianSectScoreRank.getValue()) {
            rankList = campTotalScoreRankMap.getRankList();
            myId = String.valueOf(userData.getCampId());
        } else {
            return GameErrorCode.E_XIU_XIAN_PARAM_ERROR;
        }
        // 拿榜单排名
        int myRank = -1;
        int num = 0;
        for (CrossXiuXianRank rank : rankList) {
            num++;
            if (Objects.equals(rank.getId(), myId)) {
                myRank = num;
                break;
            }
        }
        XiuXianProto.CrossXiuXianGetRankRewardRespMsg.Builder builder = XiuXianProto.CrossXiuXianGetRankRewardRespMsg.newBuilder();
        builder.setRet(0);
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setConditionType(conditionType);
        builder.setRank(myRank);
        sendPacket(GameProtocol.S_XIU_XIAN_GET_RANK_REWARD_FROM_CROSS, builder, userId);
        return 0;
    }

    /**
     * 添加被打同步消息
     */
    public void addPvpAttackSyncData(int placeId, CrossXiuXianPvpAttackHelper attack) {
        synchronized (attackSyncListMap) {
            List<CrossXiuXianPvpAttackHelper> attackSyncList = attackSyncListMap.getOrDefault(placeId, new ArrayList<>());
            attackSyncList.add(attack);
            attackSyncListMap.put(placeId, attackSyncList);
        }
    }


    /**
     * 通知游戏服condition更新值
     */
    private void notifyConditionChange(long userId, eGamePlayerEventType type, long value) {
        XiuXianProto.CrossXiuXianNotifyConditionRespMsg.Builder builder = XiuXianProto.CrossXiuXianNotifyConditionRespMsg.newBuilder();
        builder.setUserId(userId);
        builder.setConditionType(type.getValue());
        builder.setValue(value);
        sendPacket(GameProtocol.S_XIU_XIAN_NOTIFY_CONDITION_FROM_CROSS, builder, userId);
    }

    public CrossXiuXianRankListModel getUserScoreRank() {
        return userScoreRank;
    }

    private Map<Long, CrossXiuXianPvpUserData> npcUserMap = new ConcurrentHashMap<>();

    private Map<Long, CrossXiuXianNpcDataHelper> npcDataMap = new ConcurrentHashMap<>();

    private long npcId = 1;

    private CrossXiuXianPvpUserData genNpcUserData(long npcId, int campId, String param) {
        if (!npcUserMap.containsKey(npcId)) {
            CrossXiuXianPvpUserData npc = new CrossXiuXianPvpUserData();
            npc.setActivityId(config.getActivityInfo().getActivityId());
            npc.setUserId(npcId);
            // 宗门id
            npc.setCampId(campId);
            // 出生地id
            npc.setPlaceId(0);
            // 可传送时间
            npc.setTransferTime(System.currentTimeMillis());
            // 可复活时间
            npc.setReviveTime(System.currentTimeMillis());
            // 生命标识
            npc.setReviveCnt(0);
            npc.setPvpAble(true);
            // 造一份假属性
            XiuXianPveUserProperty pveProperty = npc.getPveProperty();
            List<Long> paramList = StringUtils.stringToLongList(param, "\\|");
            Map<Integer, Long> attrMap = new HashMap<>();
            attrMap.put(eXiuXianType.BattleAttrType.Hp.getValue(), paramList.get(0));
            attrMap.put(eXiuXianType.BattleAttrType.Atk.getValue(), paramList.get(1));
            attrMap.put(eXiuXianType.BattleAttrType.CritRatio.getValue(), paramList.get(2));
            attrMap.put(eXiuXianType.BattleAttrType.TenacityRatio.getValue(), paramList.get(3));
            attrMap.put(eXiuXianType.BattleAttrType.AtkSpeed.getValue(), paramList.get(4));
            attrMap.put(eXiuXianType.BattleAttrType.DodgeRatio.getValue(), paramList.get(5));
            attrMap.put(eXiuXianType.BattleAttrType.HitRatio.getValue(), paramList.get(6));
            attrMap.put(eXiuXianType.BattleAttrType.SuckRatio.getValue(), paramList.get(7));
            pveProperty.setAttrMap(attrMap);
            pveProperty.setPowerVal(paramList.get(8));
            pveProperty.setStateId(paramList.get(9).intValue());
            npc.setPveProperty(pveProperty);
            updatePvpProperty(npc);
            npcUserMap.put(npcId, npc);
            // 顺便生成一下信息
            CrossXiuXianNpcDataHelper dataHelper = new CrossXiuXianNpcDataHelper();
            dataHelper.setUserId(npcId);
            CrossXiuXianPvpCampData campData = getPvpCampData(campId);
            List<Long> list = new ArrayList<>(campData.getServerIdList());
            dataHelper.setServerId(list.get(randomHelper.next(0, list.size())));
            dataHelper.setNickName("npc" + npcId);
            dataHelper.setDecoration(String.valueOf(randomGetNpcHeadId()));
            npcDataMap.put(npcId, dataHelper);
        }
        return npcUserMap.get(npcId);
    }

    private int randomGetNpcHeadId() {
        List<Integer> list = new ArrayList<>();
        for (int i = 106055; i <= 106074; i++) {
            list.add(i);
        }
        return list.get(randomHelper.next(0, list.size()));
    }


    // =======================命令测试====================
    public void testCode(long userId, String code) {
        CrossXiuXianPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return;
        }
        // 宗门id
        int campId = userData.getCampId();
        // 设置宗主
        if ("zongzhu".equals(code)) {
            CrossXiuXianPvpCampData pvpCampData = getPvpCampData(campId);
            pvpCampData.setMajorUserId(userId);
            if (pvpCampData.getMinorUserId() == userId) {
                pvpCampData.setMinorUserId(0);
            }
            syncCampInfoToAllCampMember(campId);
        }
        // 更改宗门
        if (code.startsWith("setCampId")) {
            int id = Integer.parseInt(code.substring("setCampId".length() + 1));
            userData.setCampId(id);
        }
        // 重置积分
        if ("resetScore".equals(code)) {
            for (int id : pvpCampDataMap.keySet()) {
                CrossXiuXianPvpCampData campData = getPvpCampData(id);
                addCampScore(id, -campData.getScore());
            }
        }
        // npc开启攻击
        if ("kqgj".equals(code)) {
            npcAttack = true;
        }
        // npc取消攻击
        if ("qxgj".equals(code)) {
            npcAttack = false;
        }
        // npc开启复活
        if ("kqfh".equals(code)) {
            npcRevive = true;
        }
        // npc取消复活
        if ("qxfh".equals(code)) {
            npcRevive = false;
        }
        // 踢出指定房间所有npc
        if (code.startsWith("tNpc")) {
            int placeId = Integer.parseInt(code.substring("tNpc".length() + 1));
            synchronized (getPlaceLock(placeId)) {
                CrossXiuXianPvpPlaceData placeInfo = getPvpPlace(placeId);
                Set<Long> userList = new HashSet<>(placeInfo.getUserList());
                for (Long id : userList) {
                    if (!isNpc(id)) {
                        continue;
                    }
                    leavePlace(getPvpUserData(id), 3);
                    synchronized (npcDataMap) {
                        npcDataMap.remove(id);
                    }
                    synchronized (npcUserMap) {
                        npcUserMap.remove(id);
                    }
                }
            }
        }
        // 踢出所有npc
        if (code.startsWith("tAllNpc")) {
            for (int placeId = 1; placeId <= 18; placeId++) {
                synchronized (getPlaceLock(placeId)) {
                    CrossXiuXianPvpPlaceData placeInfo = getPvpPlace(placeId);
                    for (Long id : placeInfo.getUserList()) {
                        if (!isNpc(id)) {
                            continue;
                        }
                        leavePlace(getPvpUserData(id), 3);
                        removeNpc(id);
                    }
                }
            }
        }
        // 踢出所有npc
        if (code.startsWith("kAllNpc")) {
            for (int placeId = 5; placeId <= 18; placeId++) {
                synchronized (getPlaceLock(placeId)) {
                    CrossXiuXianPvpPlaceData placeInfo = getPvpPlace(placeId);
                    for (Long id : placeInfo.getUserList()) {
                        if (!isNpc(id)) {
                            continue;
                        }
                        CrossXiuXianPvpUserData pvpUserData = getPvpUserData(id);
                        leavePlace(pvpUserData, 3);
                        joinPlace(pvpUserData.getCampId(), pvpUserData);
                    }
                }
            }
        }
        // 增加某个宗门xxx积分
        if (code.startsWith("addCampScore")) {
            String param = code.substring("addCampScore".length() + 1);
            String[] split = param.split("#");
            addCampScore(Integer.parseInt(split[0]), Long.parseLong(split[1]));
        }
        if (code.startsWith("pvp")) {
            userData.setPvpAble(true);
            String param = code.substring("pvp".length() + 1);
            if (!StringUtils.isNullOrEmpty(param)) {
                XiuXianPveUserProperty pveProperty = userData.getPveProperty();
                List<Long> paramList = StringUtils.stringToLongList(param, "\\|");
                Map<Integer, Long> attrMap = new HashMap<>();
                attrMap.put(eXiuXianType.BattleAttrType.Hp.getValue(), paramList.get(0));
                attrMap.put(eXiuXianType.BattleAttrType.Atk.getValue(), paramList.get(1));
                attrMap.put(eXiuXianType.BattleAttrType.CritRatio.getValue(), paramList.get(2));
                attrMap.put(eXiuXianType.BattleAttrType.TenacityRatio.getValue(), paramList.get(3));
                attrMap.put(eXiuXianType.BattleAttrType.AtkSpeed.getValue(), paramList.get(4));
                attrMap.put(eXiuXianType.BattleAttrType.DodgeRatio.getValue(), paramList.get(5));
                attrMap.put(eXiuXianType.BattleAttrType.HitRatio.getValue(), paramList.get(6));
                attrMap.put(eXiuXianType.BattleAttrType.SuckRatio.getValue(), paramList.get(7));
                pveProperty.setAttrMap(attrMap);
                pveProperty.setPowerVal(paramList.get(8));
                pveProperty.setStateId(paramList.get(9).intValue());
                userData.setPveProperty(pveProperty);
                updatePvpProperty(userData);
            }
        }
        if ("xpvp".equals(code)) {
            userData.setPvpAble(false);
        }
        if (code.startsWith("effect")) {
            int param = Integer.parseInt(code.substring("effect".length() + 1));
            userData.getPvpProperty().setEffectId(param);
        }
        if (code.startsWith("randomNpc")) {
            String param = code.substring("randomNpc".length() + 1);
            int count = Integer.parseInt(param);
            for (int i = 0; i < count; i++) {
                int placeId = randomHelper.next(5, 19);
                int canJoinCamp = getCanJoinCamp(placeId);
                if (canJoinCamp == 0) {
                    continue;
                }
                StringBuilder sb = new StringBuilder();
                List<XiuXianStateConfig> stateConfigs = new ArrayList<>(config.getStateConfigMap().values());
                sb.append(randomHelper.next(1, 1000000)).append("|")
                        .append(randomHelper.next(1, 100000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(randomHelper.next(1000, 5000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(stateConfigs.get(randomHelper.next(0, stateConfigs.size() - 1)).getId()).append("|");
                CrossXiuXianPvpUserData pvpUserData = genNpcUserData(npcId++, canJoinCamp, sb.toString());
                // 加入房间
                joinPlace(placeId, pvpUserData);
            }
        }
        if (code.startsWith("addNpc1")) {
            String param = code.substring("addNpc1".length() + 1);
            String[] split = param.split("#");
            int count = Integer.parseInt(split[0]);
            for (int i = 0; i < count; i++) {
                int placeId = randomHelper.next(5, 19);
                int canJoinCamp = getCanJoinCamp(placeId);
                if (canJoinCamp == 0) {
                    continue;
                }
                CrossXiuXianPvpUserData pvpUserData = genNpcUserData(npcId++, canJoinCamp, split[1]);
                // 加入房间
                joinPlace(placeId, pvpUserData);
            }
        }
        if (code.startsWith("addNpc2")) {
            String param = code.substring("addNpc2".length() + 1);
            String[] split = param.split("#");
            int count = Integer.parseInt(split[0]);
            int placeId = Integer.parseInt(split[1]);
            for (int i = 0; i < count; i++) {
                int canJoinCamp = getCanJoinCamp(placeId);
                if (canJoinCamp == 0) {
                    break;
                }
                CrossXiuXianPvpUserData pvpUserData = genNpcUserData(npcId++, canJoinCamp, split[2]);
                // 加入房间
                joinPlace(placeId, pvpUserData);
            }
        }
        if (code.startsWith("addNpc3")) {
            String param = code.substring("addNpc3".length() + 1);
            String[] split = param.split("#");
            int count = Integer.parseInt(split[0]);
            for (int i = 0; i < count; i++) {
                int placeId = randomHelper.next(5, 19);
                CrossXiuXianPvpUserData pvpUserData = genNpcUserData(npcId++, Integer.parseInt(split[1]), split[2]);
                // 加入房间
                joinPlace(placeId, pvpUserData);
            }
        }
        if (code.startsWith("addNpc4")) {
            String param = code.substring("addNpc4".length() + 1);
            String[] split = param.split("#");
            int count = Integer.parseInt(split[0]);
            int placeId = Integer.parseInt(split[1]);
            int genCampId = Integer.parseInt(split[2]);
            for (int i = 0; i < count; i++) {
                CrossXiuXianPvpUserData pvpUserData = genNpcUserData(npcId++, genCampId, split[3]);
                // 加入房间
                joinPlace(placeId, pvpUserData);
            }
        }
        if (code.equals("clearNotice")) {
            noticeDataList.clear();
            for (LinkedList<CrossXiuXianPvpNoticeData> list : campNoticeDataMap.values()) {
                list.clear();
            }
        }
        if (code.startsWith("notice")) {
            String param = code.substring("notice".length() + 1);
            String[] split = param.split("@");
            int type = Integer.parseInt(split[0]);
            CrossXiuXianPvpNoticeData noticeData = new CrossXiuXianPvpNoticeData();
            noticeData.setActivityId(config.getActivityInfo().getActivityId());
            noticeData.setRound(getCurRound());
            noticeData.setCampId(campId);
            noticeData.setNoticeType(type);
            noticeData.setContent(split[1]);
            noticeData.setNoticeTime(System.currentTimeMillis());
            noticeData.setIsRoll(Integer.parseInt(split[2]));
            addPvpNoticeData(noticeData, userId, userId);
        }
        if (code.startsWith("gz")) {
            String param = code.substring("gz".length() + 1);
            userData.getPvpProperty().setHp(0);
            userData.setReviveTime(System.currentTimeMillis() + DateHelper.SECOND_MILLIONS * Long.parseLong(param));
            XiuXianProto.XiuXianAttackedUserSyncMsg.Builder builder = XiuXianProto.XiuXianAttackedUserSyncMsg.newBuilder();
            // 通知被打的人
            builder.setAttackUserData(parseXiuXianPvpOtherUserTemp(userData));
            builder.setAttack(parseXiuXianAttackedTemp(new CrossXiuXianPvpAttackHelper()));
            builder.setPvpUserData(parseXiuXianPvpUserDataTemp(userData));
            sendPacket(ClientProtocol.U_XIU_XIAN_ATTACKED_USER_SYNC, builder, userId);
        }
        if (code.equals("resetPlace")) {
            resetPlaceData();
        }
    }

    private int getCanJoinCamp(int placeId) {
        // 所有宗门人数计数
        CrossXiuXianPvpPlaceData placeData = getPvpPlace(placeId);
        if (placeData == null) {
            return 0;
        }
        Map<Integer, Integer> campCntMap = new HashMap<>();
        // 初始化下
        for (int campId : pvpCampDataMap.keySet()) {
            campCntMap.put(campId, 0);
        }
        for (Long userId : placeData.getUserList()) {
            CrossXiuXianPvpUserData userData = getPvpUserData(userId);
            if (userData == null || userData.getUserState() == 1) {
                continue;
            }
            campCntMap.put(userData.getCampId(), campCntMap.get(userData.getCampId()) + 1);
        }
        List<Integer> ansList = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : campCntMap.entrySet()) {
            if (entry.getValue() < config.getXIUXIAN_PVP_ROOM_PEOPLE_NUM_MAX()) {
                ansList.add(entry.getKey());
            }
        }
        if (ansList.size() == 0) {
            return 0;
        }
        return ansList.get(randomHelper.next(0, ansList.size()));
    }
}
